洛谷P3380 模板二逼平衡树(树套树,树状数组,线段树)

Posted FlashHu

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了洛谷P3380 模板二逼平衡树(树套树,树状数组,线段树)相关的知识,希望对你有一定的参考价值。

洛谷题目传送门

emm。。。题目名写了个平衡树,但是这道题的理论复杂度最优解应该还是树状数组套值域线段树吧。

就像dynamic ranking那样(蒟蒻的Sol,放一个link骗访问量233)

所有的值(包括初始a数组,操作1、3、4、5的k)全部先丢进去离散化

对于1操作查比它小的数,挑log棵线段树,找区间小于这个数的个数+1,这个还比较好像

操作2就是dynamic ranking,log棵线段树一起加减,像静态主席树求第k小一样跳,操作3 dynamic ranking里也有

操作4先求小于这个数的个数,那么前驱的排名就等于这个个数,注意特判0就好了。

操作5也是先求排名再去找这个数,排名是小于且等于这个数的个数(等于查小于这个数在值域里加+1的数排名)

拼命卡常(小技巧,发现当前跳到的点size已经为0了就不用再往下跳了),然而常数还是丑。。。说不定应该破掉非递归版跑的比递归版多多少少快一点的谣言了?

#include<cstdio>
#include<cstring>
#include<algorithm>
#define RG register
#define R RG int
#define II inline int
#define IV inline void
#define gc          if(++pi==iend)fread(pi=ibuf,1,SZ,stdin)
#define pc(C) *po=C;if(++po==oend)fwrite(po=obuf,1,SZ,stdout)
#define Q b+1,b+L+1
#define lb(X) X=lower_bound(Q,X)-b
using namespace std;
const int SZ=1<<20,N=50009,M=5000009,INF=2147483647;//卡了空间,M没到Nlog^2
char ibuf[SZ],obuf[SZ],*pi=ibuf+SZ-1,*po=obuf;
const char*iend=ibuf+SZ,*oend=obuf+SZ;
IV in(R&x){
    gc;
    while(*pi<\'-\')gc;
    x=*pi&15;gc;
    while(*pi>\'-\'){x*=10;x+=*pi&15;gc;}
}
IV out(R x){
    if(x>9)out(x/10);
    pc(x%10|\'0\');
}
int n,L,P,a[N],b[N<<1],op[N],ql[N],qr[N],qk[N];
int rt[N],lc[M],rc[M],s[M],ra[20],rs[20];
IV upd(R p,R k,R v){//更新
    for(R u,l,r,m,i=p;i<=n;i+=i&-i){
        if(!rt[i])rt[i]=++P;u=rt[i];l=1;r=L;
        while(l^r){
            s[u]+=v;m=(l+r)>>1;
            if(k<=m){r=m;if(!lc[u])lc[u]=++P;u=lc[u];}
            else  {l=m+1;if(!rc[u])rc[u]=++P;u=rc[u];}
        }
        s[u]+=v;
    }
}
II kth(R p,R k){//求第k小的值
    R i,l=1,r=L,m,sum,pa=0,ps=0;
    for(i=qr[p]  ;i;i-=i&-i)ra[++pa]=rt[i];
    for(i=ql[p]-1;i;i-=i&-i)rs[++ps]=rt[i];
    while(l^r){
        sum=0;m=(l+r)>>1;
        for(i=1;i<=pa;++i)sum+=s[lc[ra[i]]];
        for(i=1;i<=ps;++i)sum-=s[lc[rs[i]]];
        if(k<=sum){
            r=m;
            for(i=1,p=pa,pa=0;i<=p;++i)ra[++pa]=lc[ra[i]];
            for(i=1,p=ps,ps=0;i<=p;++i)rs[++ps]=lc[rs[i]];
        }
        else{
            l=m+1;k-=sum;
            for(i=1,p=pa,pa=0;i<=p;++i)ra[++pa]=rc[ra[i]];
            for(i=1,p=ps,ps=0;i<=p;++i)rs[++ps]=rc[rs[i]];
        }
    }
    return b[l];
}
II rank(R p,R x){//求离散化后的值的排名(从0计,也就是小于等于值的数的个数)
    R i,u,l,r,m,k=0;
    for(i=qr[p];i;i-=i&-i){
        u=rt[i];l=1;r=L;
        while(s[u]&&l^r){
            m=(l+r)>>1;
            if(x<=m)           r=m,u=lc[u];
            else k+=s[lc[u]],l=m+1,u=rc[u];
        }
    }
    for(i=ql[p]-1;i;i-=i&-i){
        u=rt[i];l=1;r=L;
        while(s[u]&&l^r){
            m=(l+r)>>1;
            if(x<=m)           r=m,u=lc[u];
            else k-=s[lc[u]],l=m+1,u=rc[u];
        }
    }
    return k;
}
int main(){
    R m,i,rk;
    in(n);in(m);L=n;
    for(i=1;i<=n;++i)in(a[i]);
    memcpy(b,a,(n+1)<<2);
    for(i=1;i<=m;++i){
        in(op[i]);//先存起来
        in(ql[i]);if(op[i]!=3)in(qr[i]);
        in(qk[i]);if(op[i]!=2)b[++L]=qk[i];
    }
    b[++L]=INF;sort(Q);L=unique(Q)-b-1;
    for(i=1;i<=n;++i)
        upd(i,lb(a[i]),1);
    for(i=1;i<=m;++i){
    	if(op[i]!=2)lb(qk[i]);
        switch(op[i]){
            case 1:out(rank(i,qk[i])+1);pc(\'\\n\');break;
            case 2:out(kth(i,qk[i]));pc(\'\\n\');break;
            case 3:upd(ql[i],a[ql[i]],-1);
                upd(ql[i],a[ql[i]]=qk[i],1);break;
            case 4:rk=rank(i,qk[i]);
                if(rk)out(kth(i,rk));
                else{pc(\'-\');out(INF);}pc(\'\\n\');break;
            case 5:rk=rank(i,qk[i]+1);
                out(rk>qr[i]-ql[i]?INF:kth(i,rk+1));pc(\'\\n\');
        }
    }
    fwrite(obuf,1,po-obuf,stdout);
    return 0;
}

以上是关于洛谷P3380 模板二逼平衡树(树套树,树状数组,线段树)的主要内容,如果未能解决你的问题,请参考以下文章

P3380 模板二逼平衡树(树套树)

P3380 模板二逼平衡树(树套树)

模板二逼平衡树(树套树)

[模板]洛谷T3380 二逼平衡树 线段树套Splay

洛谷3380 二逼平衡树(树套树)

「luogu3380」模板二逼平衡树(树套树)