On the three-dimensional partial order of CDQ divide and conquer (fool's detailed explanation)

CDQ divide and conquer (learning notes only)

1, Name origin

        The division of cdq comes from the national team paper of Chen Danqi (cdq) in 2009.

2, Main ideas

        After two points, first deal with the previous interval, and then affect the latter interval with the results of the previous interval.

3, Main problems

        seek Partial order Problems, such as two-dimensional partial order and three-dimensional partial order.

4, Go straight to the subject   Classic examples

       Three dimensional partial order   (my first purple question!)

        Question surface:

        have   n   Element, second   i   Elements have   ai​,bi​,ci​   Three properties, set   f(i)   Express satisfaction   aj​≤ai​   And   bj​≤bi​   And   cj​≤ci​   And   j≠i   of   j   Number of.

        about   D ∈ [0,n], find   f(i)=d   Number of.

        Three attributes, 3D

        Solution: reduce the dimension and divide it into one dimension and one dimension.

        Solution steps:

        1. Processing the first dimension (a in the structure): take the first dimension as the primary keyword, the second dimension as the secondary keyword, and the third dimension as the third keyword in ascending sort   Sort. (no odd sort row)

bool cmp1(node x,node y)
{
  if(x.a==y.a)
  {
      if(x.b==y.b)return x.c<y.c;
      return x.b<y.b;
  }
  return x.a<y.a;
}

        2. Deal with the second dimension (b in the structure): the idea of merging  , Divide the sequence that has been arranged in the first dimension into two parts, so that the first half and the second half are always in s [J]. A < = a [i]. A (J < = mid < I), and then take the second dimension as the main keyword and the third dimension as the second in the two intervals         To sort the keyword.

bool cmp2(node x,node y)
{
  if(x.b==y.b)return x.c<y.c;
  return x.b<y.b;
}
 1 void cdq(int l,int r)
 2 {
 3   if(l==r)return;
 4   int mid=(l+r)/2;
 5   cdq(l,mid);
 6   cdq(mid+1,r);
 7   sort(s+l,s+1+mid,cmp2);
 8   sort(s+mid+1,s+1+r,cmp2);
 9   int j=l;
10   for(int i=mid+1;i<=r;i++)
11   {
12       while(s[j].b<=s[i].b&&j<=mid)
13       {
14         add(s[j].c,s[j].sa);
15         j++;
16     }
17     s[i].ans+=qzh(s[i].c);
18   }  
19   for(int i=l;i<j;i++)
20     add(s[i].c,-s[i].sa); 
21   /*memset(w,0,sizeof(w));*/
22   //It was used memset But to TLE 
23 }

(it was found that the line number can be added)

        1 ~ 8: dichotomy + row of the second dimension

        3. Processing the third dimension (c in the structure): lines 9 ~ 23. It is processed during merging. If there is B < = [mid + 1, R] in [l,mid], the previous element may be an answer to the latter element (or a previous item). At this time, the previous element will be used               The third dimension of the element is stored in the sa value as the subscript of the tree array; If b > b in [mid + 1, R] in [l,mid], the b value of all elements after the current element in the previous interval is greater than the b value of the current element in the later interval. There is no need to continue searching. You can propose the current element in the later interval           The answer to the prime is the prefix sum in the tree array at this time (you can understand it with the thinking of dp and tree array)

lowbit:

int lowbit(int x)
{
  return x&(-x);
}

  Add tree array:

void add(int x,int y)
{
  while(x<=k)
  {
      w[x]+=y;
      x+=lowbit(x);
  }
}

Propose s[i].ans prefix and:

int qzh(int x)
{
  int e=0;
  while(x>0)
  {
      e+=w[x];
      x-=lowbit(x);
  }
  return e;
}

        4. Save the answer: because the question requires f(i)=d to save, you can reopen an array (similar to a bucket). For a subscript i, its answer is its ans value + x value, and then change the storage method according to the meaning of the question.

Save answer:

for(int i=1;i<=m;i++)
    anss[s[i].ans+s[i].sa-1]+=s[i].sa;

 

To sum up: difficult and error prone points

1. The weight shall be removed when it is just stored, and the weight shall be compared with the latter one.

2. The first dimension is sorted directly with sort, so that the first dimension of the former part is always less than or equal to the first dimension of the latter part when merging and sorting later, so as to eliminate the impact of the first dimension on processing.

3. The second dimension is in the sort row after dichotomy, which plays an auxiliary role in comparison.

4. The third dimension is compared during merging and used as the subscript of the tree array.

5. In case by case discussion, one is to add elements to the tree array, and the other is to get the answer according to the current tree array.

6. Remember to clear the tree array (because it is temporary) and cannot use memset (TLE).

7. Remember to add the same elements when storing.

Eh, OK, code:

#include<bits/stdc++.h>
using namespace std;
int n,k,w[200010],anss[200010],m=0,top=0; 
struct node
{
  int a,b,c,sa,ans;
  //a,b,c:Three attributes 
  //sa:same The first two letters, elements that repeat with them
  //ans:The answer of the current element (smaller than its three attributes) 
};
node s[200010];
bool cmp1(node x,node y)
{
  if(x.a==y.a)
  {
      if(x.b==y.b)return x.c<y.c;
      return x.b<y.b;
  }
  return x.a<y.a;
}
bool cmp2(node x,node y)
{
  if(x.b==y.b)return x.c<y.c;
  return x.b<y.b;
}
int lowbit(int x)
{
  return x&(-x);
}
void add(int x,int y)
{
  while(x<=k)
  {
      w[x]+=y;
      x+=lowbit(x);
  }
}
int qzh(int x)
{
  int e=0;
  while(x>0)
  {
      e+=w[x];
      x-=lowbit(x);
  }
  return e;
}
void cdq(int l,int r)
{
  if(l==r)return;
  int mid=(l+r)/2;
  cdq(l,mid);
  cdq(mid+1,r);
  sort(s+l,s+1+mid,cmp2);
  sort(s+mid+1,s+1+r,cmp2);
  int j=l;
  for(int i=mid+1;i<=r;i++)
  {
      while(s[j].b<=s[i].b&&j<=mid)
      {
        add(s[j].c,s[j].sa);
        j++;
    }
    s[i].ans+=qzh(s[i].c);
  }  
  for(int i=l;i<j;i++)
    add(s[i].c,-s[i].sa); 
  /*memset(w,0,sizeof(w));*/
  //It was used memset But to TLE 
}
int main()
{
  scanf("%d%d",&n,&k);
  for(int i=1;i<=n;i++)
    scanf("%d%d%d",&s[i].a,&s[i].b,&s[i].c);
  sort(s+1,s+1+n,cmp1);
  for(int i=1;i<=n;i++)
  {
    top++;
    if(s[i].a!=s[i+1].a||s[i].b!=s[i+1].b||s[i].c!=s[i+1].c)
    //There was always a problem at the beginning of the test because it was used s[i]and s[i-1]To compare, error reason:
    //Different from the latter bit ratio, it means to end the previous process (even if the process length is 1 (different from the front and back));
    //And compared with the previous one, top Zero, not counted 
    {
      m++;
      s[m].a=s[i].a;
      s[m].b=s[i].b;
      s[m].c=s[i].c;
      s[m].sa=top;
      top=0;
    }
  }
  cdq(1,m);
  for(int i=1;i<=m;i++)
    anss[s[i].ans+s[i].sa-1]+=s[i].sa;
  for(int i=0;i<n;i++)//Why 0~n?See the meaning of the topic d+1 
    printf("%d\n",anss[i]);
  return 0;
}

 

Posted on Sun, 05 Dec 2021 13:37:00 -0500 by dotbob