前言
怕自己忘,给自己留一个板子
以下代码均为洛谷【模板】三维偏序代码
树套树
先排序。
第一层树是一个树状数组。
第二层是一个线段树。
排完序后,枚举i,查询b小于自己的数所建的树,这一层通过树状数组快速枚举。
在线段树内二分找c小于自己的数.
code
#include<bits/stdc++.h>
using namespace std;
inline char gc(){
static char buf[1<<5],*p1=buf,*p2=buf;
return (p1==p2)&&(p2=(p1=buf)+fread(buf,1,1<<5,stdin),p1==p2)?EOF:*p1++;
}
inline int read(){
register int data=0,w=1;
register char ch=0;
while(ch<'0'||ch>'9')ch=gc(),ch=='-'?w=-1:w=1;
while(ch>='0'&&ch<='9'){
data=data*10+ch-'0';
ch=gc();
}
return data*w;
}
const int _ = 200050;
struct orz{
int a,b,c;
int cnt;
bool operator <(const orz &x) const {
if(a!=x.a)return a<x.a;
if(b!=x.b)return b<x.b;
return c<x.c;
}
bool operator ==(const orz&x)const {
return (a==x.a&&b==x.b&&c==x.c);
}
}p[_],s[_];
int n,k,m;
int rt[_],val[_*200],c[_*200][2];
int tot[_<<1],cnt;
inline int query(int T,int l,int r,int pd){
if(!T||r<=pd) return val[T];
register int mid = (l+r)>>1;
register int sum=0;
if (mid+1<=pd)sum+=query(c[T][1],mid+1,r,pd);
sum+=query(c[T][0],l,mid,pd);
return sum;
}
void modify(int &T,int l,int r,int pos,int data){
if(!T)T=++cnt;
val[T]+=data;
if(l==r)return;
register int mid = (l+r)>>1;
if(pos<=mid)modify(c[T][0],l,mid,pos,data);
else modify(c[T][1],mid+1,r,pos,data);
return;
}
int main(){
n=read();
k=read();
for(register int i=1;i<=n;++i){
p[i]=(orz){read(),read(),read()};
}
sort(p+1,p+n+1);
for(register int i=1;i<=n;++i){
if(s[m]==p[i])++s[m].cnt;
else s[++m]=p[i],s[m].cnt=1;
}
for(register int i=1;i<=m;++i){
int yyy=0;
for(register int j=s[i].b;j;j-=j&-j){
yyy+=query(rt[j],1,k,s[i].c);
}
tot[yyy+s[i].cnt-1]+=s[i].cnt;
for(register int j=s[i].b;j<=k;j+=j&-j){
modify(rt[j],1,k,s[i].c,s[i].cnt);
}
}
for(register int i=0;i<n;++i)printf("%d\n",tot[i]);
}
CDQ分治
最外面一层是CDQ,然后还有树状数组.大佬说可以直接套三层CDQ;
为了避免重复(题目中描述里有等于号),所以先去重,再计算.
code
#include<bits/stdc++.h>
#define LL long long
using namespace std;
namespace zjy_io{
inline char gc(){
static char buf[1<<6],*p1=buf,*p2=buf;
return (p1==p2)&&(p2=(p1=buf)+fread(buf,1,1<<6,stdin),p1==p2)?EOF:*p1++;
}
template <class T>
inline void read(T&data){
data=0;
register char ch=0;
register int caa=1;
while(ch!='-'&&(ch<'0'||ch>'9'))ch=gc();
ch=='-'?caa=-1,ch=gc():caa=1;
while(ch<='9'&&ch>='0'){
data=(data<<3)+(data<<1)+(ch^48);
ch=gc();
}
data*=caa;
}
inline char Getchar(){
register char ch=0;
while(ch<'A'||ch>'Z')ch=gc();return ch;
}
}
using namespace zjy_io;
const int _ = 1.03e5;
int Tot[_],ans[_],n,n_,k;
int Tree[_<<1],sum[_];
struct two{
int x,y;
} Q[_];
int Q_cnt;
inline int lowbit(register int g){return (-g)&g;}
inline void modify(register int loc,register int zh){
for(register int i=loc;i<=k;i+=lowbit(i))Tree[i]+=zh;
}
inline int Query(register int loc){
int ret=0;
for(register int i=loc;i;i-=lowbit(i))ret+=Tree[i];
return ret;
}
struct element{
int a,b,c,num;
}s[_],q[_],ss[_];
bool operator == (element a,element b){
return (a.a==b.a)&&(a.b==b.b)&&(a.c==b.c);
}
bool cmp(register element x,register element y){
if(x.a!=y.a) return x.a<y.a;
if(x.b!=y.b)return x.b<y.b;
return x.c<y.c;
}
void CDQ(int L,int R){
if(L==R)return;
register int mid = (L+R)>>1;
CDQ(L,mid);
CDQ(mid+1,R);
register int pin1=L,pin2=mid+1,ppl=L;
for(;pin2<=R;++pin2){
while(s[pin1].b<=s[pin2].b&&pin1<=mid){
modify(s[pin1].c,sum[s[pin1].num]);
Q[++Q_cnt]=(two){s[pin1].c,sum[s[pin1].num]};
q[ppl]=s[pin1];++pin1;++ppl;
}
Tot[s[pin2].num]+=Query(s[pin2].c);
q[ppl]=s[pin2];++ppl;
}
for(register int i=1;i<=Q_cnt;++i)modify(Q[i].x,-Q[i].y);Q_cnt=0;
while(pin1<=mid){
q[ppl]=s[pin1];++pin1;++ppl;
}
for(register int i=L;i<=R;++i){
s[i]=q[i];
}
return;
}
int main(){
read(n_),read(k);
for(register int i=1;i<=n_;++i)read(ss[i].a),read(ss[i].b),read(ss[i].c),ss[i].num=i;
sort(ss+1,ss+n_+1,cmp);
s[n=1]=ss[1];
int c=1;
for(register int i=2;i<=n_;++i){
if(ss[i]==s[n]){++c;continue;}
sum[s[n].num]=c;
s[++n]=ss[i],c=1;
}
sum[s[n].num]=c;
CDQ(1,n);
for(register int i=1;i<=n_;++i)
ans[Tot[i]+sum[i]-1]+=sum[i];
for(register int i=0;i<n_;++i)
cout<<ans[i]<<endl;
}
然后还有直接套两层CDQ的,具体来说就是用打标记的方法一层一层消掉。