以前完全没有看过 CDQ 分治的东西。然后听说就是分治右区间,左区间然后计算左区间对右区间的贡献。然后上生物课的时候实在无聊然后随便yy了一下三维偏序,感觉不是很难(?
首先要去重然后按第一维排序。然后每一个数要记录自己在原序列中出现了几次。cdq的时候考虑先分治左区间,分治右区间,然后再让左右区间分别按照第二维排序。由于我们已经保证右边的第一维一定大于左边的第一维,所以我们 two pointers+BIT 就可以算出对于右区间的每个元素,有多少个左区间的元素使得其第二维和第三维都比他小,
洛谷模板P3810
#include<bits/stdc++.h>
#define int long long
#define rep(i,a,b) for(register int i=(a);i<=(b);i++)
#define per(i,a,b) for(register int i=(a);i>=(b);i--)
using namespace std;
const int N=4e5+9;
inline int read() {
register int x=0, f=1; register char c=getchar();
while(c<'0'||c>'9') {if(c=='-') f=-1; c=getchar();}
while(c>='0'&&c<='9') {x=(x<<3)+(x<<1)+c-48,c=getchar();}
return x*f;
}
int n,k,id[N],val[N],cnt,ans[N];
struct node {int x,y,z,v,ans;} a[N];
bool cmp(const node &x,const node &y) {
return x.x==y.x?(x.y==y.y?x.z<y.z:x.y<y.y):x.x<y.x;
}
bool operator == (const node &x,const node &y) {
return x.x==y.x&&x.y==y.y&&x.z==y.z;
}
bool cmpc(const node &x,const node &y) {
return x.y==y.y?x.z<y.z:x.y<y.y;
}
void uniq() {
sort(a+1,a+n+1,cmp);
rep(i,1,n) {
id[++cnt]=i, val[cnt]=1;
while(a[i+1]==a[i]) val[cnt]++, i++;
}
rep(i,1,cnt) a[i]=a[id[i]], a[i].v=val[i];
}
int s[N];
int lb(int x) {return x&(-x);}
void add(int x,int v) {for(;x<=k;x+=lb(x)) s[x]+=v;}
int query(int x,int ret=0) {for(;x;x-=lb(x)) ret+=s[x]; return ret;}
void cdq(int l,int r) {
if(l==r) return;
int mid=(l+r)/2;
cdq(l,mid), cdq(mid+1,r);
sort(a+l,a+mid+1,cmpc), sort(a+mid+1,a+r+1,cmpc);
int i=l,j=mid+1;
for(;j<=r;j++) {
while(a[i].y<=a[j].y&&i<=mid) add(a[i].z,a[i].v), i++;
a[j].ans+=query(a[j].z);
}
for(j=l;j<i;j++) add(a[j].z,-a[j].v);
}
signed main() {
n=read(), k=read();
rep(i,1,n) {
a[i].x=read(), a[i].y=read(), a[i].z=read();
}
uniq();
cdq(1,cnt);
rep(i,1,cnt) ans[a[i].ans+a[i].v-1]+=a[i].v;
rep(i,0,n-1) printf("%lld
",ans[i]);
return 0;
}