cdq分治入门--BZOJ3262: 陌上花开
n<=100000个人,每个人三个属性Ai,Bi,Ci,一个人i的等级为Ai>=Aj,Bi>=Bj,Ci>=Cj的人数,求每个等级有多少人。
裸的三维偏序。按照常规思路,一维排序,一维归并,一维利用单调性或用树状数组维护,这里选择后者。
先按Ai排序,然后在分治过程中,solve(l,mid),solve(mid+1,r),然后考虑(l,mid)对(mid+1,r)答案的贡献,先把这两部分分别按B排序,然后两个指针一起扫,扫的过程中,把C的值作下标丢进树状数组,查询时相当于树状数组前缀和。
思路很好,可样例过不了。
原因:在计算过程中默认后面对前面是没有贡献的,但按Ai排序后,相同的Ai值可能引起后面对前面的贡献。
方法:保证后面对前面无贡献,一开始就先按A再按B最后按C排序即可。
那还有重复的呢?去重呗!
1 #include<stdio.h> 2 #include<string.h> 3 #include<stdlib.h> 4 #include<algorithm> 5 //#include<iostream> 6 using namespace std; 7 8 int n,m; 9 #define maxn 200011 10 int ord[maxn],tmpord[maxn]; 11 struct BIT 12 { 13 int a[maxn]; 14 BIT() {memset(a,0,sizeof(a));} 15 void add(int x,int v) {for (;x<=n;x+=x&-x) a[x]+=v;} 16 int query(int x) {int ans=0;for (;x;x-=x&-x) ans+=a[x];return ans;} 17 }t; 18 19 struct Point 20 { 21 int x,y,z,cnt; 22 bool operator < (const Point &b) const 23 {return x<b.x || (x==b.x && y<b.y) || (x==b.x && y==b.y && z<b.z);} 24 }q[maxn],p[maxn]; 25 int ans[maxn],ansnum[maxn]; 26 void solve(int L,int R) 27 { 28 if (L==R) {ans[L]+=p[L].cnt-1;ord[L]=L;return;} 29 const int mid=(L+R)>>1; 30 solve(L,mid); 31 solve(mid+1,R); 32 int i=L,j=mid+1,k=L; 33 while (i<=mid && j<=R) 34 { 35 if (p[ord[i]].y<=p[ord[j]].y) 36 { 37 tmpord[k++]=ord[i]; 38 t.add(p[ord[i]].z,p[ord[i]].cnt); 39 i++; 40 } 41 else 42 { 43 tmpord[k++]=ord[j]; 44 ans[ord[j]]+=t.query(p[ord[j]].z); 45 j++; 46 } 47 } 48 for (;j<=R;j++) ans[ord[j]]+=t.query(p[ord[j]].z),tmpord[k++]=ord[j]; 49 for (int ii=L;ii<i;ii++) t.add(p[ord[ii]].z,-p[ord[ii]].cnt); 50 for (;i<=mid;i++) tmpord[k++]=ord[i]; 51 for (int x=L;x<=R;x++) ord[x]=tmpord[x]; 52 } 53 54 int lisan[maxn]; 55 int main() 56 { 57 scanf("%d%d",&n,&m); 58 for (int i=1;i<=n;i++) 59 { 60 scanf("%d%d%d",&q[i].x,&q[i].y,&q[i].z); 61 lisan[i]=q[i].z; 62 } 63 sort(lisan+1,lisan+1+n); 64 for (int i=1;i<=n;i++) q[i].z=lower_bound(lisan+1,lisan+1+n,q[i].z)-lisan; 65 sort(q+1,q+1+n); 66 int tot=0;q[0].x=-0x3f3f3f3f; 67 for (int i=1;i<=n;i++) 68 { 69 if (q[i-1].x==q[i].x && q[i-1].y==q[i].y && q[i-1].z==q[i].z) p[tot].cnt++; 70 else p[++tot]=q[i],p[tot].cnt=1; 71 } 72 solve(1,tot); 73 for (int i=1;i<=tot;i++) ansnum[ans[i]]+=p[i].cnt; 74 for (int i=0;i<n;i++) printf("%d\n",ansnum[i]); 75 return 0; 76 }