CDQ分治
思想就是分治!
然后就是每次二分区间,然后在分治统计左右区间之后,考虑统计跨越左右区间的数对。
给个模板题 陌上花开。
我们对于这个三维偏序问题,可以考虑CDQ分治。
先对于原序列按照a,b,c排序,这样保证a的单调增。
然后分治,对于每个小区间按照b,a,c排序,这样在右边区间的a大于左边区间的前提下,我们满足b单调增。我们枚举j区间选取的元素,然后取移动指针i保证i位置上的b小于j位置上的b,把i位置上的c加入树状数组。每个j在树状数组上统计一遍答案。这就是全过程。
但是本题有一个问题,它有相同的元素,分治的时候会统计少。
但是我们可以合并相同的元素,就可以了。
会CDQ分治了吗?上代码就懂了。
code:
#include<bits/stdc++.h>
using namespace std;
#define LL long long
#define file(a) freopen(#a".in","r",stdin),freopen(#a".out","w",stdout)
inline int read(){
int s=0,f=1;char ch=getchar();
while(ch<'0'||'9'<ch) {if(ch=='-') f=-1;ch=getchar();}
while('0'<=ch&&ch<='9') {s=s*10+(ch^48);ch=getchar();}
return s*f;
}
const int MAXN=2e5+3;
const int N=1e5+3;
int num;
struct Bit{
int c[MAXN];
inline void add(int x,int k){
for(;x<=num;x+=(x&-x) ) c[x]+=k;
}
inline int find(int y){
int res=0;
for(;y;y-=(y&-y) ) res+=c[y];
return res;
}
}c;
int n;
struct node{
int a,b,c,cnt,ans;
inline friend bool operator ==(node x,node y){
return (x.a==y.a and x.b==y.b and x.c==y.c);
}
inline friend bool operator !=(node x,node y){
return !(x==y);
}
}f[N],p[N];
bool cmp(node x,node y){
if(x.a==y.a){
if(x.b==y.b){
return x.c<y.c;
}
return x.b<y.b;
}
return x.a<y.a;
}
bool cmp2(node x,node y){
if(x.b==y.b){
if(x.a==y.a){
return x.c<y.c;
}
return x.a<y.a;
}
return x.b<y.b;
}
int ans[N];
void cdq_solve(int l,int r){
if(l==r) return;
int mid=(l+r)>>1;
cdq_solve(l,mid);cdq_solve(mid+1,r);
sort(p+l,p+mid+1,cmp2);
sort(p+mid+1,p+r+1,cmp2);
int i=l;
for(int j=mid+1;j<=r;++j){
while(i<=mid and p[i].b<=p[j].b){
c.add(p[i].c,p[i].cnt);++i;
}
p[j].ans+=c.find(p[j].c);
}
for(int k=l;k<i;++k) c.add(p[k].c,-p[k].cnt);
}
int main(){
//file(a);
n=read();num=read();
for(int i=1;i<=n;++i){
f[i].a=read();
f[i].b=read();
f[i].c=read();
}
sort(f+1,f+n+1,cmp);
int cnt=1;
int num=n;n=0;
for(int i=1;i<=num;++i){
if(f[i]!=f[i+1]){
p[++n]=f[i];
p[n].cnt=cnt;
p[n].ans=0;
cnt=1;
//printf("%d %d %d %d\n",p[n].a,p[n].b,p[n].c,p[n].cnt);
}else{
++cnt;
}
}
cdq_solve(1,n);
for(int i=1;i<=n;++i){
ans[p[i].cnt+p[i].ans-1]+=p[i].cnt;
}
for(int i=0;i<num;++i){
printf("%d\n",ans[i]);
}
return 0;
}