bzoj3196: Tyvj 1730 二逼平衡树

来源:互联网 发布:流程优化小组 编辑:程序博客网 时间:2024/05/17 22:03

传送门
蛋疼树套树。
外层线段树维护区间。
内层treap维护数字出现情况。
打完这道我整个人都不好了。

#include<cstdio>#include<cstdlib>#include<iostream>#include<cmath>#include<cstring>#include<algorithm>#define N 200005#define M 3000005#define inf 0x3f3f3f3fusing namespace std;int n,m,sz,ans,fl,x,y,k;int a[N],rt[N];int ls[M],rs[M],rnd[M],v[M],s[M],w[M];void update(int k){    s[k]=s[ls[k]]+s[rs[k]]+w[k];}void rturn(int &k){    int t=ls[k];    ls[k]=rs[t];    rs[t]=k;    s[t]=s[k];    update(k);    k=t;}void lturn(int &k){    int t=rs[k];    rs[k]=ls[t];    ls[t]=k;    s[t]=s[k];    update(k);    k=t;}void insert(int &k,int num){    if (!k){        k=++sz;        s[k]=w[k]=1;        v[k]=num;        rnd[k]=rand();        return;    }    s[k]++;    if (num==v[k]) w[k]++;    else if (num<v[k]){        insert(ls[k],num);        if (rnd[ls[k]]<rnd[k]) rturn(k);     }    else{        insert(rs[k],num);        if (rnd[rs[k]]<rnd[k]) lturn(k);    }}void del(int &k,int num){    if (v[k]==num){        if (w[k]>1){            w[k]--; s[k]--;            return;        }        if (ls[k]*rs[k]==0) k=ls[k]+rs[k];        else if (rnd[ls[k]]<rnd[rs[k]]){            rturn(k); del(k,num);        }        else{            lturn(k); del(k,num);        }    }    else if (num<v[k]){        del(ls[k],num); s[k]--;    }    else{        del(rs[k],num); s[k]--;    }}void build(int k,int l,int r,int x,int num){    insert(rt[k],num);    if (l==r) return;    int mid=(l+r)/2;    if (x<=mid) build(k*2,l,mid,x,num);    else build(k*2+1,mid+1,r,x,num);}void askrk(int k,int num){    if (!k) return;    if (num==v[k]){        ans+=s[ls[k]];        return;    }    if (num<v[k]) askrk(ls[k],num);    else{        ans+=s[ls[k]]+w[k];        askrk(rs[k],num);    }}void getrk(int k,int l,int r,int x,int y,int num){    if (l==x&&r==y){        askrk(rt[k],num);        return;    }    int mid=(l+r)/2;    if (y<=mid) getrk(k*2,l,mid,x,y,num);    else if (x>mid) getrk(k*2+1,mid+1,r,x,y,num);    else getrk(k*2,l,mid,x,mid,num),getrk(k*2+1,mid+1,r,mid+1,y,num);}void getnum(int x,int y,int z){    int l=0,r=inf,s;    while (l<=r){        int mid=(l+r)/2;        ans=1;        getrk(1,1,n,x,y,mid);        if (ans<=z) l=mid+1,s=mid;        else r=mid-1;    }    printf("%d\n",s);}void change(int k,int l,int r,int x,int num,int y){    del(rt[k],y);    insert(rt[k],num);    if (l==r) return;    int mid=(l+r)/2;    if (x<=mid) change(k*2,l,mid,x,num,y);    else change(k*2+1,mid+1,r,x,num,y);}void pre(int k,int num){    if (!k) return;    if (v[k]<num){        ans=max(ans,v[k]);        pre(rs[k],num);    }    else pre(ls[k],num);}void suc(int k,int num){    if (!k) return;    if (v[k]>num){        ans=min(ans,v[k]);        suc(ls[k],num);    }    else suc(rs[k],num);}void askpre(int k,int l,int r,int x,int y,int num){    if (l==x&&r==y){        pre(rt[k],num);        return;    }    int mid=(l+r)/2;    if (y<=mid) askpre(k*2,l,mid,x,y,num);    else if (x>mid) askpre(k*2+1,mid+1,r,x,y,num);    else askpre(k*2,l,mid,x,mid,num),askpre(k*2+1,mid+1,r,mid+1,y,num);}void asksuc(int k,int l,int r,int x,int y,int num){    if (l==x&&r==y){        suc(rt[k],num);        return;    }    int mid=(l+r)/2;    if (y<=mid) asksuc(k*2,l,mid,x,y,num);    else if (x>mid) asksuc(k*2+1,mid+1,r,x,y,num);    else asksuc(k*2,l,mid,x,mid,num),asksuc(k*2+1,mid+1,r,mid+1,y,num);}int main(){    scanf("%d%d",&n,&m);    for (int i=1;i<=n;i++) scanf("%d",&a[i]);    for (int i=1;i<=n;i++) build(1,1,n,i,a[i]);    for (int i=1;i<=m;i++){        scanf("%d%d%d",&fl,&x,&y);        if (fl!=3) scanf("%d",&k);        if (fl==1){            ans=1;            getrk(1,1,n,x,y,k);            printf("%d\n",ans);        }        if (fl==2)            getnum(x,y,k);        if (fl==3){            change(1,1,n,x,y,a[x]);            a[x]=y;         }        if (fl==4){            ans=0;            askpre(1,1,n,x,y,k);            printf("%d\n",ans);        }        if (fl==5){            ans=inf;            asksuc(1,1,n,x,y,k);            printf("%d\n",ans);        }    }}
0 0
原创粉丝点击