三维偏序(陌上花开) CDQ分治
十分巧妙。
Code:
#include <cstdio> #include <algorithm> #include <cstring> #define setIO(s) freopen(s".in","r",stdin) #define maxn 200000 #define N 3000000 #define ll long long using namespace std; int k,n; int C[N],ans[maxn],cnt[maxn]; int lowbit(int x){ return x&(-x); } void add(int pos,int x){ while(pos<=k) C[pos]+=x,pos+=lowbit(pos); } int query(int pos){ int sum=0; while(pos>0) sum+=C[pos],pos-=lowbit(pos); return sum; } struct OPT{ int x,y,z,w,idx; }arr[maxn],opt[maxn]; int cmpx(OPT a,OPT b){ return (a.x==b.x&&a.y==b.y)?(a.z<b.z):((a.x==b.x)?a.y<b.y:a.x<b.x); } int cmpy(OPT a,OPT b){ return (a.y==b.y)?a.z<b.z:a.y<b.y; } void solve(int l,int r){ if(l>=r) return; int mid=(l+r)>>1; solve(l,mid),solve(mid+1,r); sort(opt+l,opt+mid+1,cmpy),sort(opt+mid+1,opt+r+1,cmpy); int p=l,q=mid+1; for(;q<=r;++q){ while(opt[p].y<=opt[q].y&&p<=mid) add(opt[p].z,opt[p].w),++p; ans[opt[q].idx]+=query(opt[q].z); } for(int i=l;i<p;++i) add(opt[i].z,-opt[i].w); } int main() { //setIO("input"); scanf("%d%d",&n,&k); for(int i=1;i<=n;++i)scanf("%d%d%d",&arr[i].x,&arr[i].y,&arr[i].z); sort(arr+1,arr+1+n,cmpx); int u=n,cc=0; n=0; for(int i=1;i<=u;++i){ ++cc; if(arr[i].x!=arr[i+1].x||arr[i].y!=arr[i+1].y||arr[i].z!=arr[i+1].z) opt[++n]=arr[i],opt[n].w=cc,opt[n].idx=n,cc=0; } solve(1,n); for(int i=1;i<=n;i++) cnt[ans[opt[i].idx]+opt[i].w-1]+=opt[i].w; for(int i=0;i<u;++i) printf("%d\n",cnt[i]); return 0; }