BZOJ 3262 陌上花开 ——CDQ分治
【题目分析】
多维问题,我们可以按照其中一维排序,然后把这一维抽象的改为时间。
然后剩下两维,就像简单题那样,排序一维,树状数组一维,按照时间分治即可。
挺有套路的一种算法。
时间的抽象很巧妙。
同种的花需要处理,合并在一起计算即可。
【代码】
#include <cstdio> #include <cstring> #include <iostream> #include <vector> #include <algorithm> using namespace std; #define ll long long #define maxn 300005 struct flo{int a,b,c,id;}q[maxn],eq[maxn],nq[maxn]; int cnt,k,top=0,ans[maxn],T,c[maxn]; vector <int> v[maxn]; bool cmp(flo x,flo y) { if (x.a==y.a&&x.b==y.b) return x.c<y.c; if (x.a==y.a) return x.b<y.b; return x.a<y.a; } bool cmp2(flo x,flo y) { if (x.b==y.b&&x.c==y.c) return x.a<y.a; if (x.b==y.b) return x.c<y.c; return x.b<y.b; } struct Bit_Tree{ int v[maxn]; void init(){memset(v,0,sizeof v);} void add(int x,int f) {for (;x<=k;x+=x&(-x)) v[x]+=f;} int sum(int x) { int ret=0; for (;x;x-=x&(-x)) ret+=v[x]; return ret; } }t; void solve(int l,int r) { if (l==r) return ; int mid=(l+r)/2; for (int i=l;i<=r;++i) { if (eq[i].a<=mid) t.add(eq[i].c,v[eq[i].id].size()); if (eq[i].a>mid) { int tmp=t.sum(eq[i].c); for (int j=0;j<v[eq[i].id].size();++j) ans[v[eq[i].id][j]]+=tmp; } } int p1=l,p2=mid+1; for (int i=l;i<=r;++i) if (eq[i].a<=mid) t.add(eq[i].c,-v[eq[i].id].size()); for (int i=l;i<=r;++i) if (eq[i].a<=mid) nq[p1++]=eq[i]; else nq[p2++]=eq[i]; for (int i=l;i<=r;++i) eq[i]=nq[i]; solve(l,mid); solve(mid+1,r); } int main() { scanf("%d%d",&cnt,&k); for (int i=1;i<=cnt;++i) scanf("%d%d%d",&q[i].a,&q[i].b,&q[i].c),q[i].id=i; sort(q+1,q+cnt+1,cmp); for (int i=1;i<=cnt;++i) { if (!top) eq[++top]=q[i],v[top].push_back(q[i].id); else if (eq[top].a!=q[i].a||eq[top].b!=q[i].b||eq[top].c!=q[i].c) eq[++top]=q[i],v[top].push_back(q[i].id); else v[top].push_back(q[i].id); eq[top].id=top; } for (int i=1;i<=top;++i) eq[i].a=i; sort(eq+1,eq+top+1,cmp2); solve(1,top); for (int i=1;i<=top;++i) for (int j=0;j<v[eq[i].id].size();++j) ans[v[eq[i].id][j]]+=v[eq[i].id].size()-1; for (int i=1;i<=cnt;++i) c[ans[i]]++; for (int i=0;i<cnt;++i) printf("%d\n",c[i]); }