bzoj 3196 二逼平衡树 树套树

都是泪,调了一晚。代码能力++。
查询区间排名k,时间复杂度nlog³n,bzoj能A,但是tyvj TLE 两个点,求各路大神指错打脸。
另外推荐一个OJ http://cogs.pro/cogs/ 给数据,很良心。

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<stack>
#define maxn 1000005
//#include<windows.h>
using namespace std;
stack<int> S;
inline void read(int &a)
{
    a=0;int h=1;
    char c=getchar();
    while(c<'0'||c>'9')
    {
        if(c=='-') h=-1;
        c=getchar();
    }
    while(c>='0'&&c<='9')
    {
        a*=10;a+=c-'0';
        c=getchar();
    }
    a*=h;
}
struct xds
{
    int l,r;
    int root;
}tree[400005];
int a[50005];
int tot;
int key[maxn],sz[maxn],cnt[maxn];
int fa[maxn],ch[maxn][2];
int D,inf=1e9;
int Min=1e9,Max=0;
//===============================================
bool dir(int x)
{return x==ch[fa[x]][1];}
void up(int x)
{sz[x]=sz[ch[x][0]]+sz[ch[x][1]]+cnt[x];}
void rotate(int x)
{
    bool b=dir(x);
    int y=fa[x];
    int z=fa[y];
    int a=ch[x][!b];
    if(z) ch[z][dir(y)]=x;
    else    tree[D].root=x;
    fa[x]=z;ch[x][!b]=y;
    fa[y]=x;ch[y][b]=a;
    if(a) fa[a]=y;
    up(y);up(x);
}
void Splay(int x)
{
    while(fa[x]!=tree[D].root)
    {
        int y=fa[x];int z=fa[y];
        if(z==tree[D].root)
            rotate(x);
        else
        {
            bool b=dir(x),c=dir(y);
            if(b^c) {rotate(x);rotate(x);}
            else    {rotate(y);rotate(x);}
        }
    }
}
void splay(int x)
{
    while(x!=tree[D].root)
    {
        if(fa[x]==tree[D].root)
            rotate(x);
        else
        {
            int y=fa[x];
            bool b=dir(x),c=dir(y);
            if(b^c) {rotate(x);rotate(x);}
            else    {rotate(y);rotate(x);}
        }
    }
}
void insert(int x,int &y,int last)
{
    if(y==0)
    {
        if(!S.empty())
        {
            y=S.top();
            S.pop();
        }
        else y=++tot;
        key[y]=x;fa[y]=last;
        sz[y]=1;cnt[y]=1;
        ch[y][0]=0;ch[y][1]=0;
//      splay(y);
        return ;
    }
    if(x==key[y])
    {
        sz[y]++;
        cnt[y]++;
//      splay(y);
        return ;
    }
    sz[y]++;
    if(x>key[y])insert(x,ch[y][1],y);
    else        insert(x,ch[y][0],y);
}
int d,pre,nxt;
int t1,t2;
void f_pre(int x)
{
    for(;x;x=ch[x][key[x]<d])
        if(key[x]<d){pre=max(pre,key[x]);t1=x;}
}
void f_nxt(int x)
{
    for(;x;x=ch[x][key[x]<=d])
        if(key[x]>d){nxt=min(nxt,key[x]);t2=x;}
}
//===============================================
void dfs(int x,int y,int last)
{
    if(x==0) return ;
    fa[y]=last;key[y]=key[x];
    sz[y]=sz[x];cnt[y]=cnt[x];
    if(ch[x][1])
    {
        ch[y][1]=++tot;
        dfs(ch[x][1],ch[y][1],y);
    }
    if(ch[x][0])
    {
        ch[y][0]=++tot;
        dfs(ch[x][0],ch[y][0],y);
    }
}
void build(int dq,int l,int r)
{
    tree[dq].l=l;
    tree[dq].r=r;
    tree[dq].root=++tot;
    if(l==r)
    {
        sz[tot]=1;cnt[tot]=1;key[tot]=a[l];
        fa[tot]=tree[dq>>1].root;
        return ;
    }
    int mid=(l+r)>>1;
    build(dq<<1,l,mid);
    build(dq<<1|1,mid+1,r);
    D=dq;
    dfs(tree[dq<<1].root,tree[dq].root,0);
    for(int i=mid+1;i<=r;i++)
        insert(a[i],tree[dq].root,0);
}
//===============================================
int L,R,X;
int CNT;
int f_n_r(int dq)//1
{
    if(tree[dq].l>=L&&tree[dq].r<=R)
    {
        t1=inf;d=X;pre=-inf;
        f_pre(tree[dq].root);
        if(t1==inf) return 0;
        D=dq;splay(t1);
        return sz[t1]-sz[ch[t1][1]];
    }
    int ans=0;
    int mid=(tree[dq].l+tree[dq].r)>>1;
    if(mid>=L)  ans+=f_n_r(dq<<1);
    if(mid<R)   ans+=f_n_r(dq<<1|1);
    return ans;
}
void find_pre(int dq)
{
    if(tree[dq].l>=L&&tree[dq].r<=R)
    {
        f_pre(tree[dq].root);
        return ;
    }
    int mid=(tree[dq].l+tree[dq].r)>>1;
    if(mid>=L)  find_pre(dq<<1);
    if(mid<R)   find_pre(dq<<1|1);
}
void find_nxt(int dq)
{
    if(tree[dq].l>=L&&tree[dq].r<=R)
    {
        f_nxt(tree[dq].root);
        return ;
    }
    int mid=(tree[dq].l+tree[dq].r)>>1;
    if(mid>=L)  find_nxt(dq<<1);
    if(mid<R)   find_nxt(dq<<1|1);
}
//===============================================
void Find(int i,int k)
{
    for(;i;i=ch[i][key[i]<k])
        if(key[i]==k) 
        {splay(i);return ;}
}
int pos;
void del()
{
    int dq=tree[D].root;
    if(cnt[dq]>1)
    {cnt[dq]--;sz[dq]--;return ;}
    if(!ch[dq][0])
    {
        int a=ch[dq][1];
        tree[D].root=a;
        fa[a]=0;return ;
    }
    if(!ch[dq][1])
    {
        int a=ch[dq][0];
        tree[D].root=a;
        fa[a]=0;return ;
    }
    d=key[dq];
    pre=-inf;f_pre(dq);Splay(t1);
    int a=ch[dq][1];
    S.push(dq);
    tree[D].root=t1;fa[t1]=0;ch[t1][1]=a;
    fa[a]=t1;up(t1);
}
void change(int dq)//3
{
    if(tree[dq].l==pos&&tree[dq].r==pos)
    {
        key[tree[dq].root]=X;
        return ;
    }
    if(tree[dq].l<=pos&&tree[dq].r>=pos)
    {
        D=dq;Find(tree[dq].root,a[pos]);
        del();insert(X,tree[dq].root,0);
    }
    int mid=(tree[dq].l+tree[dq].r)>>1;
    if(mid>=pos)change(dq<<1);
    else        change(dq<<1|1);
}
//===============================================
int K;
int ask()
{
    int l=0,r=1e8;
    while(true)
    {
        int ans=(l+r)>>1;
        X=ans;
        if(f_n_r(1)+1<=K)
            l=ans;
        else    r=ans;
        if(r-l==1)return l;
    }
}
int main()
{
//  freopen("input8.in","r",stdin);
//  freopen("ans.txt","w",stdout);
//  int SS=GetTickCount();
    int n,m;scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
        read(a[i]);
    build(1,1,n);
    int op;
    int T=0;
    for(int i=1;i<=m;i++)
    {
        read(op);
        if(op==1)
        {
            read(L);read(R);read(X);
            int Q=f_n_r(1)+1;
            printf("%d\n",Q);
        }
        if(op==2)
        {
            read(L);read(R);read(K);
            int Q=ask();
            printf("%d\n",Q);
        }
        if(op==3)
        {
            read(pos);read(X);
            change(1);a[pos]=X;
        }
        if(op==4)
        {
            read(L);read(R);
            pre=-inf;read(d);find_pre(1);
            printf("%d\n",pre);
        }
        if(op==5)
        {
            read(L);read(R);
            nxt=inf;read(d);find_nxt(1);
            printf("%d\n",nxt);
        }
    }
//  int TT=GetTickCount();
//  cout<<"h "<<TT-SS;
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值