【BZOJ 3196】[Tyvj 1730]二逼平衡树

题目描述

传送门–Portal

题目解析

题目都说了是平衡树,肯定就是平衡树板题,又因为是区间操作,树套树就行了。(第一次写,就写的线段树套Splay,感觉Splay跑得shi慢。。。一定是蒟蒻自带大常数的原因)唯一要思考的就是如何找到区间第k大,很简单,二分判定就行了。
又因为Splay的点更新问题,Wa了我3个小时,以后一定要记住,只要有修改,一定要更新!!!而且是更新当前节点的所有信息,尤其是标记啊~~
悲伤得难以自已
这里写图片描述

放放福利,再给你们一个数据生成器吧(注意,标准数据中是没有无解的情况的)。

#include<cassert>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<cstdio>
#include<ctime>
#include<vector>

using namespace std;

#define MAXN 50000
#define MAXM 50000
#define MAXVAL 100000000
int GetRand(int L, int R) {
    int Len = R - L + 1;
    int Ret = rand() * rand() % Len + L;
    return Ret;
}

int main() {
    //freopen("data5.in", "w", stdout);
    srand(time(NULL));
    int n = GetRand(MAXN, MAXN);
    int m = GetRand(MAXM, MAXM);
    int L, R, Pos, Val, Cmd, K;

    printf("%d %d\n", n, m);
    for(int i = 1; i <= n; i++) {
        Val = GetRand(0 , MAXVAL);
        if(i == 1)
            printf("%d", Val);
        else
            printf(" %d", Val);
    }
    puts("");
    while(m-- > 0) {
        Cmd = GetRand(1, 5);
        L = GetRand(1, n);
        R = GetRand(L, n);  
        switch(Cmd) {

            case 1:
                K = GetRand(0, MAXVAL);
                printf("1 %d %d %d\n", L,R, K);
                break;
            case 2:
                K = GetRand(1, R-L+1);
                printf("2 %d %d %d\n", L,R, K);
                break;
            case 3:
                Pos = GetRand(1, n);
                Val = GetRand(0, MAXVAL);
                printf("3 %d %d\n", Pos, Val);
                break;
            case 4:
            case 5:
                K = GetRand(0, MAXVAL);
                printf("%d %d %d %d\n", Cmd, L,R, K);
                break;  
        }
    }
    fclose(stdout);
    return 0;
}

代码

/**************************************************************
    Problem: 3196
    User: bzjudge2
    Language: C++
    Result: Accepted
    Time:8888 ms
    Memory:61840 kb
****************************************************************/

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<cstring>
using namespace std;

#define MAXN 50000
#define MAXM 50000
#define MAXLOG 25
#define INF 0x3f3f3f3f
typedef long long int LL;

template<class T>
void Read(T &x){
    x=0;char c=getchar();bool flag=0;
    while(c<'0'||'9'<c){if(c=='-')flag=1;c=getchar();}
    while('0'<=c&&c<='9'){x=x*10+c-'0';c=getchar();}
    if(flag)x=-x;
}

int A[MAXN+10];
int n,m;

int root[MAXN*3];
int fa[MAXN*MAXLOG*2+10];
int ch[MAXN*MAXLOG*2+10][2];
int val[MAXN*MAXLOG*2+10];
int cnt[MAXN*MAXLOG*2+10],sz[MAXN*MAXLOG*2+10];
int New;

void init(){
    memset(root,0,sizeof(root));
    New=0;
}

void updata(int x){
    sz[x]=cnt[x]+sz[ch[x][0]]+sz[ch[x][1]];
}

void rotate(int x){
    int f=fa[x];
    bool flag=(ch[f][1]==x);

    ch[f][flag]=ch[x][flag^1];
    fa[ch[x][flag^1]]=f;
    if(fa[f])ch[fa[f]][ch[fa[f]][1]==f]=x;
    fa[x]=fa[f];
    ch[x][flag^1]=f;
    fa[f]=x;

    updata(f);
    updata(x);
}

void Splay(int id,int x,int goal){
    int f,ff;
    for(;(f=fa[x])!=goal;rotate(x)){
        if((ff=fa[f])!=goal){
            if((ch[ff][1]==f)==(ch[f][1]==x))
                rotate(f);
            else rotate(x);
        }
    }
    if(goal==0)root[id]=x;
    updata(x);
}

int Newnode(int w,int f,int ls,int rs){
    int x=++New;
    val[x]=w,fa[x]=f;
    cnt[x]=sz[x]=1;
    ch[x][0]=ls,ch[x][1]=rs;

    return x;
}

int queryrank(int id,int w){
    int rn=0;
    int x=root[id];
    while(x){
        if(w<val[x])x=ch[x][0];
        else if(w==val[x]){
            rn+=sz[ch[x][0]];
            break;
        }
        else{
            rn+=sz[ch[x][0]]+cnt[x];
            x=ch[x][1];
        }
    }

    return rn;
}

int nxt(int id,int w,bool flag){
    int x=root[id],f=0;
    while(x){
        f=x;
        if(val[x]==w)break;
        else x=ch[x][val[x]<w];
    }

    if((val[f]>w&&flag==1)||(val[f]<w&&flag==0))return f;

    Splay(id,f,0);
    x=ch[f][flag];
    while(ch[x][flag^1])
        x=ch[x][flag^1];
    return x;
}

void insert(int id,int w){
    int x=root[id],f=0;
    while(x){
        if(val[x]==w){
            ++cnt[x];
            Splay(id,x,0);
            return;
        }
        else{
            f=x;
            x=ch[x][val[x]<w];
        }
    }

    x=Newnode(w,f,0,0);
    if(f)ch[f][val[f]<w]=x;

    Splay(id,x,0);
}

void del(int id,int w){
    int pos1=nxt(id,w,0),pos2=nxt(id,w,1);
    Splay(id,pos1,0);
    Splay(id,pos2,pos1);

    if(ch[pos2][0]){
        if(cnt[ch[pos2][0]]>1){
            --cnt[ch[pos2][0]];
            --sz[ch[pos2][0]];
        }
        else{
            fa[ch[pos2][0]]=0;
            ch[pos2][0]=0;
        }

        updata(pos2);
        updata(pos1);
    }
}

int L[MAXN*3],R[MAXN*3];

void build(int l,int r,int x){
    L[x]=l,R[x]=r;

    insert(x,-INF);
    insert(x,INF);
    for(int i=l;i<=r;++i)insert(x,A[i]);

    if(L[x]==R[x])return;

    int mid=(l+r)>>1;
    build(l,mid,x<<1);
    build(mid+1,r,x<<1|1);
}

int l,r,pos,w,ori_w,new_w;
int QueryRank(int x){
    if(l<=L[x]&&R[x]<=r)return queryrank(x,w)-1;
    else{
        int mid=(L[x]+R[x])>>1;
        int rn=0;
        if(l<=mid)rn+=QueryRank(x<<1);
        if(mid<r)rn+=QueryRank(x<<1|1);

        return rn;
    }
}

int minval=INF,maxval=-INF;
int QueryKth(int ll,int rr,int kth){
    l=ll,r=rr;

    int lval=minval,rval=maxval,midval;
    int ans=0;
    while(lval<=rval){
        midval=(lval+rval)>>1;

        w=midval;
        if(QueryRank(1)<kth){
            ans=midval;
            lval=midval+1;
        }
        else rval=midval-1;
    }

    return ans;
}

void Change(int x){
    del(x,ori_w);
    insert(x,new_w);

    if(L[x]==R[x])return;

    int mid=(L[x]+R[x])>>1;
    if(pos<=mid)Change(x<<1);
    else Change(x<<1|1);
}

int QueryBefore(int x){
    if(l<=L[x]&&R[x]<=r)return val[nxt(x,w,0)];
    else{
        int mid=(L[x]+R[x])>>1;
        int rn=-INF;
        if(l<=mid)rn=max(rn,QueryBefore(x<<1));
        if(mid<r)rn=max(rn,QueryBefore(x<<1|1));

        return rn;
    }
}

int QueryNxt(int x){
    if(l<=L[x]&&R[x]<=r)return val[nxt(x,w,1)];
    else{
        int mid=(L[x]+R[x])>>1;
        int rn=INF;
        if(l<=mid)rn=min(rn,QueryNxt(x<<1));
        if(mid<r)rn=min(rn,QueryNxt(x<<1|1));

        return rn;
    }
}

int main(){
    //freopen("data.in","r",stdin);
    //freopen("data.out","w",stdout);

    Read(n),Read(m);

    init();

    for(int i=1;i<=n;++i){
        Read(A[i]);
        minval=min(minval,A[i]),maxval=max(maxval,A[i]);
    }

    build(1,n,1);

    int a,b,c,d;
    for(int i=1;i<=m;++i){minval=min(minval,A[i]),maxval=max(maxval,A[i]);
        Read(d);

        if(d==1){
            Read(l),Read(r),Read(w);
            printf("%d\n",QueryRank(1)+1);
        }
        else if(d==2){
            Read(a),Read(b),Read(c);
            printf("%d\n",QueryKth(a,b,c));
        }
        else if(d==3){
            Read(pos),Read(new_w);
            ori_w=A[pos];
            Change(1);
            A[pos]=new_w;
            minval=min(minval,A[pos]),maxval=max(maxval,A[pos]);
        }
        else if(d==4){
            Read(l),Read(r),Read(w);
            printf("%d\n",QueryBefore(1));
        }
        else{
            Read(l),Read(r),Read(w);
            printf("%d\n",QueryNxt(1));
        }
     }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值