[BZOJ3262]陌上花开
陌上花开
题目描述
输入格式
输出格式
样例
膜拜CDQ小姐姐
CDQ分治一般情况下会用来解决三维偏序问题,一般的套路是第一维直接快排,然后进行CDQ分治,在分治过程中通过归并再次使得第二维有序,当然,不归并可以再次对部分数据快排,打起来肯定快排爽,不过过程中要处理的东西处理起来应该也有点难受,如果代码能力是大佬,就当刚才什么都没说,由于进行操作前已经保证了第一维有序,左区间均可对右区间作出贡献,所以在归并第二维时第一维已经不重要了,第三维的有序一般通过树状数组等数据结构实现,需要注意的是对于维护第三维的数据结构需要每次清空,但是千万不要memset之类的全部清空,别觉得memset一句话就快,他就是O(n),只需要清空当前区间,不然很可能T到飞起,上述就是CDQ分治的基本思路
陌上花开是CDQ最经典的三维偏序问题,思路就是上述那个,这题需要注意的是由于等于的存在,要在排序之后去重,其他的,树状数组记得打对,存的是第三维,记得不管是数组范围还是操作结尾,均是k而不是n,来自WA了6遍的调了一天半的过来人的提醒,图就不贴了,丢人
1 #include<cstdio> 2 #include<iostream> 3 #include<algorithm> 4 #define maxn 100100 5 using namespace std; 6 struct node{ 7 int s,c,m,sum,js; 8 }a[maxn],gb[maxn]; 9 int n,k,tot; 10 int c[maxn*2],ans[maxn]; 11 bool cmp(const node &a,const node &b) 12 { 13 if(a.s!=b.s) return a.s<b.s; 14 if(a.c!=b.c) return a.c<b.c; 15 return a.m<b.m; 16 } 17 int lowbit(int x) 18 { 19 return x&(-x); 20 } 21 void add(int x,int w) 22 { 23 for(int i=x;i<=k;i+=lowbit(i)) c[i]+=w; 24 } 25 int getsum(int w) 26 { 27 int ans=0; 28 for(int i=w;i;i-=lowbit(i)) ans+=c[i]; 29 return ans; 30 } 31 void cdq(int l,int r) 32 { 33 if(l==r) return ; 34 int mid=(l+r)>>1,ll=l,rr=mid+1,zz=l; 35 cdq(l,mid); cdq(mid+1,r); 36 while(ll<=mid&&rr<=r) 37 { 38 if(a[ll].c<=a[rr].c) {add(a[ll].m,a[ll].js); gb[zz++]=a[ll++];} 39 else {a[rr].sum+=getsum(a[rr].m); gb[zz++]=a[rr++];} 40 } 41 while(ll<=mid) {add(a[ll].m,a[ll].js); gb[zz++]=a[ll++];} 42 while(rr<=r) {a[rr].sum+=getsum(a[rr].m); gb[zz++]=a[rr++];} 43 for(int i=l;i<=r;++i) 44 { 45 if(i<=mid) add(a[i].m,-a[i].js); 46 a[i]=gb[i]; 47 } 48 } 49 int main() 50 { 51 scanf("%d%d",&n,&k); 52 for(int i=1;i<=n;++i) scanf("%d%d%d",&a[i].s,&a[i].c,&a[i].m); 53 sort(a+1,a+n+1,cmp); 54 for(int i=1;i<=n;++i) 55 { 56 if(a[i].s==a[tot].s&&a[i].c==a[tot].c&&a[i].m==a[tot].m) a[tot].js++; 57 else {a[++tot].s=a[i].s; a[tot].c=a[i].c; a[tot].m=a[i].m; a[tot].js=1;} 58 } 59 cdq(1,tot); 60 for(int i=1;i<=tot;++i) ans[a[i].sum+a[i].js-1]+=a[i].js; 61 for(int i=0;i<n;++i) printf("%d\n",ans[i]); 62 return 0; 63 }