BZOJ 3262: 陌上花开 CDQ
这个题大部分人用了离散然后水之,然而.....作为一只蒟蒻我并没有想到离散,而是直接拿两个区间一个对应n,一个对应k来搞,当然这两个区间是对应的,我把第一维排序,第二维CDQ,第三维树状数组,然而由于我们二分第二维的时候他的区间[1,k]和数列区间[1,n]并不重合所以我们在二分第一个区间时对应二分第二个区间,注意我们二分地一个区间的时候由于相等的也会造成影响所以我把它搞了一个重复处理和二分的时候把中间的数抠出来,因为中间的数的确把第一维比他小且第二维比他小的数的比他小的第三维都搞完了,注意二分的时候的几个边界
#include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #define N 100000 #define K 200000 using namespace std; inline int read() { int sum=0; char ch=getchar(); while(ch<'0'||ch>'9')ch=getchar(); while(ch>='0'&&ch<='9') { sum=(sum<<1)+(sum<<3)+ch-'0'; ch=getchar(); } return sum; } int Ans[N+10]; int C[K+10]; int n,k; inline void update(int pos,int x) { while(pos<=k) { C[pos]+=x; pos+=pos&(-pos); } } inline int get_sum(int pos) { int sum=0; while(pos>0) { sum+=C[pos]; pos-=pos&(-pos); } return sum; } struct TT { int a,b,c,id; }A[N+10],temp[N+10]; int comp(const TT a,const TT b) { return a.a<b.a||(a.a==b.a&&a.b<b.b)||(a.a==b.a&&a.b==b.b&&a.c<b.c); } void CDQ(int z,int y,int l,int r) { if(l==r)return; if(z>y)return; int mid=(z+y)>>1; for(int i=l,to=0;i<=r;i+=to) { if(A[i].b<=mid) { int j=0; while(A[i+j].a==A[i].a&&A[i+j].b==A[i].b&&i+j<=r) update(A[i+j].c,1),j++; to=j; } if(A[i].b>=mid) { int j=0; while(A[i+j].a==A[i].a&&A[i+j].b==A[i].b&&i+j<=r) Ans[A[i+j].id]+=A[i].b==mid?get_sum(A[i+j].c)-1:get_sum(A[i+j].c),j++; to=j; } } for(int i=l;i<=r;i++) if(A[i].b<=mid) update(A[i].c,-1); int l1=l,l2=0; for(int i=l;i<=r;i++) if(A[i].b<mid) temp[l1++]=A[i]; l2=l1; for(int i=l;i<=r;i++) if(A[i].b>mid) temp[l2++]=A[i]; for(int i=l;i<=r;i++) A[i]=temp[i]; if(l1!=l)CDQ(z,mid-1,l,l1-1); if(l1!=l2)CDQ(mid+1,y,l1,l2-1); } inline void Init() { n=read(),k=read(); for(int i=1;i<=n;i++) { A[i].a=read(); A[i].b=read(); A[i].c=read(); A[i].id=i; } sort(A+1,A+n+1,comp); } int Get[N+10]; inline void work() { CDQ(1,k,1,n); for(int i=1;i<=n;i++) Get[Ans[i]]++; for(int i=0;i<=n-1;i++) printf("%d\n",Get[i]); } int main() { Init(); work(); }
苟利国家生死以, 岂因祸福避趋之。