CDQ 分治

以前完全没有看过 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;
}
原文地址:https://www.cnblogs.com/TetrisCandy/p/14443410.html