三维偏序

7 篇文章 0 订阅
5 篇文章 0 订阅

前言

怕自己忘,给自己留一个板子
以下代码均为洛谷【模板】三维偏序代码

树套树

先排序。
第一层树是一个树状数组。
第二层是一个线段树。
排完序后,枚举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的,具体来说就是用打标记的方法一层一层消掉。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值