象限查询

Quadrant Queries

本文关键字:查询      更新时间:2023-10-16

我几乎已经解决了使用延迟传播的段树的 Interviewstreet 的这个象限查询问题,但我仍然得到错误的答案,所以我在我的代码中需要帮助。

这是个问题:

象限查询

平面中有 N 个点。第 i 个点具有坐标 (xi, yi(。执行以下查询:

  1. 反射点 i 和 j 之间的所有点,包括沿 X 轴的点。此查询表示为 X i j
  2. 反射点 i 和 j 之间的所有点,包括沿 Y 轴的点。此查询表示为Y i j
  3. 计算点 i 和 j 之间的点(包括位于 4 个象限中的每一个(之间的点数。此查询表示为C i j

输入:

第一行包含 N,即点数。N行紧随其后。

第 i 行包含由空格分隔的 xi 和 yi。

下一行包含 Q 查询数。接下来的 Q 行分别包含一个查询,分别包含上述形式之一的查询。

所有索引均为 1 个索引。

输出:

为类型 C i j 的每个查询输出一行。相应的行包含 4 个整数;指数在 [i..j]分别在第1、2、3和4象限。

约束:

1 <= N <= 100000
1 <= Q <= 100000
You may assume that no point lies on the X or the Y axis.
All (xi,yi) will fit in a 32-bit signed integer
In all queries, 1 <=i <=j <=N

示例输入:

4
1 1
-1 1
-1 -1
1 -1
5
C 1 4
X 2 4
C 3 4
Y 1 2
C 1 3

示例输出:

1 1 1 1
1 1 0 0
0 2 0 1

解释:

当查询显示 X i j 时,这意味着取索引 i 和 j 之间的所有点,包括并反映沿 X 轴的这些点。这里的 i 和 j 与点的坐标无关。它们是指数。I 指点 I,j 指点 J

C 1 4要求您"考虑索引在 {1,2,3,4} 中的点集。在这些点中,有多少分别位于第一、第二、第三和第四四边形?答案显然是1 1 1 1。

接下来,我们沿 X 轴反映索引 '2 4' 之间的点。所以新的坐标是:

1 1
-1 -1
-1 1
1 1

现在C 3 4是"考虑在 {3,4} 中具有索引的点集。在这些点中,有多少分别位于第一、第二、第三和第四四边形?点 3 位于象限 2,点 4 位于象限 1。所以答案是 1 1 0 0。

当前代码

这是我在 c 中的解决方案:

void query(int node, int b, int e, int i, int j, char ch)
{
      if(L[node][0]!=0 || L[node][1]!=0)
    {
      if(b!=e){
      L[2*node+1][0]=L[node][0];
      L[2*node+1][1]=L[node][1];
      L[2*node+2][0]=L[node][0];
      L[2*node+2][1]=L[node][1];
      }
      if(L[node][0]%2!=0)
      {
      tmp=Q[node][0];
      Q[node][0]=Q[node][3];
      Q[node][3]=tmp;
      tmp=Q[node][1];
      Q[node][1]=Q[node][2];
      Q[node][2]=tmp;
      }
      if(L[node][1]%2!=0)
      {
      tmp=Q[node][0];
      Q[node][0]=Q[node][1];
      Q[node][1]=tmp;
      tmp=Q[node][2];
      Q[node][2]=Q[node][3];
      Q[node][3]=tmp;
      }
      L[node][0]=0;
      L[node][1]=0;
    }
      if (i > e || j < b)
          return ;

      if (b >= i && e <= j)
      {
    if(ch == 'C'){
    ans[0]+=Q[node][0];
    ans[1]+=Q[node][1];
    ans[2]+=Q[node][2];
    ans[3]+=Q[node][3];
    }
    if(ch == 'X')
    {
      if(b!=e){
      L[2*node+1][0]++;
      L[2*node+2][0]++;
      }
      tmp=Q[node][0];
      Q[node][0]=Q[node][3];
      Q[node][3]=tmp;
      tmp=Q[node][1];
      Q[node][1]=Q[node][2];
      Q[node][2]=tmp;
    }
    if(ch == 'Y')
    {
      if(b!=e){
      L[2*node+1][1]++;
      L[2*node+2][1]++;
      }
      tmp=Q[node][0];
      Q[node][0]=Q[node][1];
      Q[node][1]=tmp;
      tmp=Q[node][2];
      Q[node][2]=Q[node][3];
      Q[node][3]=tmp;
    }
    return ;
      }

       query(2 * node +1, b, (b + e) / 2, i, j,ch);
      query(2 * node + 2, (b + e) / 2 + 1, e, i, j,ch);

    Q[node][0]=Q[2*node+1][0] + Q[2*node+2][0];
    Q[node][1]=Q[2*node+1][1] + Q[2*node+2][1];
    Q[node][2]=Q[2*node+1][2] + Q[2*node+2][2];
    Q[node][3]=Q[2*node+1][3] + Q[2*node+2][3];
    return ;
}

如果我正确理解了您的算法,那么您正在使用 L 数组来跟踪是否需要翻转一系列点,但将实际翻转推迟到有必要。

在这种情况下,我认为这些行可能存在问题:

void query(int node, int b, int e, int i, int j, char ch)
{
  if(L[node][0]!=0 || L[node][1]!=0)
  {
    if(b!=e){
      L[2*node+1][0]=L[node][0];
      L[2*node+1][1]=L[node][1];
      L[2*node+2][0]=L[node][0];
      L[2*node+2][1]=L[node][1];
    }

假设 L[node][0] 是 1,而 L[2*node+1][0] 已经是 1。 这意味着前面的某个步骤想要翻转 2*node+1 的节点,然后这一步也想翻转这些节点。 这些翻转应该抵消,L[2*node+1][0] 应该变为零。

我认为您应该将这些行更改为使用异或,以便取消双翻转:

void query(int node, int b, int e, int i, int j, char ch)
{
  if(L[node][0]!=0 || L[node][1]!=0)
  {
    if(b!=e){
      L[2*node+1][0]^=L[node][0];
      L[2*node+1][1]^=L[node][1];
      L[2*node+2][0]^=L[node][0];
      L[2*node+2][1]^=L[node][1];
    }

(或者也许我误解了这种方法!