「学习笔记」替罪羊树

「学习笔记」替罪羊树

其实早就会了……开一篇占个坑。

复杂度不会证,具体可见丽洁姐的论文。

模板

\(Code\ Below:\)

#include <bits/stdc++.h>
using namespace std;
const int maxn=100000+10;
const int inf=0x3f3f3f3f;
const double alpha=0.75;
int n,rt,sz,ch[maxn][2],fa[maxn],siz[maxn],val[maxn],sta[maxn],top;

inline bool balance(int x)
{
    return 1.0*max(siz[ch[x][0]],siz[ch[x][1]])<alpha*siz[x];
}

inline void recycle(int x)
{
    if(ch[x][0]) recycle(ch[x][0]);
    sta[++top]=x;
    if(ch[x][1]) recycle(ch[x][1]);
}

int build(int l,int r)
{
    int mid=(l+r)>>1,x=sta[mid];
    ch[x][0]=ch[x][1]=0;
    if(l<mid) fa[ch[x][0]=build(l,mid-1)]=x;
    if(mid<r) fa[ch[x][1]=build(mid+1,r)]=x;
    siz[x]=siz[ch[x][0]]+siz[ch[x][1]]+1;
    return x;
}

inline void rebuild(int x)
{
    top=0;recycle(x);
    int y=fa[x],k=(ch[y][1]==x),z=build(1,top);
    ch[y][k]=z;fa[z]=y;
    if(x==rt) rt=z;
}

inline void insert(int v)
{
    if(!rt){rt=++sz;siz[rt]=1;val[rt]=v;return;}
    int x=rt,y,k;
    while(1)
    {
        siz[x]++;k=(val[x]<=v);y=x;x=ch[x][k];
        if(!x){x=++sz;ch[y][k]=x;fa[x]=y;siz[x]=1;val[x]=v;break;}
    }
    y=0;
    for(;x;x=fa[x])
        if(!balance(x)) y=x;
    if(y) rebuild(y);
}

inline void erase(int x)
{
    if(ch[x][0]&&ch[x][1])
    {
        int y=ch[x][0];
        while(ch[y][1]) y=ch[y][1];
        val[x]=val[y];x=y;
    }
    int y=fa[x],k=(ch[y][1]==x),z=ch[x][0]?ch[x][0]:ch[x][1];
    ch[y][k]=z;fa[z]=y;
    for(;y;y=fa[y]) siz[y]--;
    if(x==rt) rt=z;
}

inline int findid(int v)
{
    int x=rt,k;
    while(x)
    {
        if(val[x]==v) return x;
        k=(val[x]<=v);x=ch[x][k];
    }
    return -1;
}

inline int findrnk(int v)
{
    int x=rt,ans=0;
    while(x)
    {
        if(val[x]>=v) x=ch[x][0];
        else ans+=siz[ch[x][0]]+1,x=ch[x][1];
    }
    return ans+1;
}

inline int findkth(int k)
{
    int x=rt;
    while(x)
    {
        if(siz[ch[x][0]]>=k) x=ch[x][0];
        else
        {
            k-=siz[ch[x][0]];
            if(k==1) return val[x];
            k--;x=ch[x][1];
        }
    }
    return -1;
}

inline int findpre(int v)
{
    int x=rt,ans=-inf;
    while(x)
    {
        if(val[x]<v) ans=max(ans,val[x]),x=ch[x][1];
        else x=ch[x][0];
    }
    return ans;
}

inline int findsuc(int v)
{
    int x=rt,ans=inf;
    while(x)
    {
        if(val[x]>v) ans=min(ans,val[x]),x=ch[x][0];
        else x=ch[x][1];
    }
    return ans;
}

int main()
{
    scanf("%d",&n);
    int op,x;
    while(n--)
    {
        scanf("%d%d",&op,&x);
        if(op==1) insert(x);
        if(op==2)
        {
            x=findid(x);
            if(x>0) erase(x);
        }
        if(op==3) printf("%d\n",findrnk(x));
        if(op==4) printf("%d\n",findkth(x));
        if(op==5) printf("%d\n",findpre(x));
        if(op==6) printf("%d\n",findsuc(x));
    }
    return 0;
}

没有人的算术

好题!

因为 \((x,y)\) 最多有 \(m\) 对,我们考虑用一个平衡树存下所有的二元组,然后 \(O(1)\) 查询 \(rank\)

具体的动态标号可以去看论文中 \(O(1)\) 查先后关系的算法。

最大值可以用线段树维护,时间复杂度 \(O(n\log n)\)

\(Code\ Below:\)

#include <bits/stdc++.h>
using namespace std;
const int maxn=500000+10;
const double alpha=0.75;
int n,m,pos[maxn];double a[maxn];

inline int read()
{
    register int x=0,f=1;char ch=getchar();
    while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
    while(isdigit(ch)){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}
    return (f==1)?x:-x;
}

void print(int x)
{
    if(x<0){putchar('-');x=-x;}
    if(x>9) print(x/10);
    putchar(x%10+'0');
}

struct data
{
    int l,r;
    data(int _l=0,int _r=0):l(_l),r(_r){}
};
inline bool operator < (const data &x,const data &y)
{
    return a[x.l]<a[y.l]||(a[x.l]==a[y.l]&&a[x.r]<a[y.r]);
}
inline bool operator == (const data &x,const data &y)
{
    return x.l==y.l&&x.r==y.r;
}

namespace SG
{

int rt,sz,R,ch[maxn][2],siz[maxn],sta[maxn],top;data val[maxn];

inline bool balance(int x)
{
    return 1.0*max(siz[ch[x][0]],siz[ch[x][1]])<alpha*siz[x];
}

inline void recycle(int x)
{
    if(ch[x][0]) recycle(ch[x][0]);
    sta[++top]=x;
    if(ch[x][1]) recycle(ch[x][1]);
}

int build(int l,int r,double _l,double _r)
{
    int mid=(l+r)>>1,x=sta[mid];double mv=(_l+_r)/2;
    ch[x][0]=ch[x][1]=0;a[x]=mv;
    if(l<mid) ch[x][0]=build(l,mid-1,_l,mv);
    if(mid<r) ch[x][1]=build(mid+1,r,mv,_r);
    siz[x]=siz[ch[x][0]]+siz[ch[x][1]]+1;
    return x;
}

inline void rebuild(int &x,double l,double r)
{
    top=0;recycle(x);x=build(1,top,l,r);
}

inline int insert(int &x,double l,double r,data v)
{
    double mid=(l+r)/2;int z;
    if(!x){x=++sz;a[x]=mid;val[x]=v;siz[x]=1;return x;}
    if(val[x]==v) return x;
    else
    {
        siz[x]++;
        if(val[x]<v) z=insert(ch[x][1],mid,r,v);
        else z=insert(ch[x][0],l,mid,v);
    }
    if(balance(x))
    {
        if(R)
        {
            if(ch[x][0]==R) rebuild(ch[x][0],l,mid);
            else rebuild(ch[x][1],mid,r);
            R=0;
        }
    }
    else R=x;
    return z;
}

}

using SG::rt;
using SG::R;

namespace ST
{

#define lson (rt<<1)
#define rson (rt<<1|1)

int mx[maxn<<2];

inline int cmp(int x,int y)
{
    return a[pos[x]]>=a[pos[y]]?x:y;
}

inline void pushup(int rt)
{
    mx[rt]=cmp(mx[lson],mx[rson]);
}

void build(int l,int r,int rt)
{
    if(l == r){mx[rt]=l;return;}
    int mid=(l+r)>>1;
    build(l,mid,lson);build(mid+1,r,rson);pushup(rt);
}

inline void update(int x,int l,int r,int rt)
{
    if(l == r){mx[rt]=l;return;}
    int mid=(l+r)>>1;
    if(x <= mid) update(x,l,mid,lson);
    else update(x,mid+1,r,rson);
    pushup(rt);
}

int query(int L,int R,int l,int r,int rt)
{
    if(L <= l && r <= R) return mx[rt];
    int mid=(l+r)>>1;
    if(L > mid) return query(L,R,mid+1,r,rson);
    if(R <= mid) return query(L,R,l,mid,lson);
    return cmp(query(L,R,l,mid,lson),query(L,R,mid+1,r,rson));
}

}

int main()
{
    n=read(),m=read();
    a[0]=-1;SG::insert(rt,0,1,data(0,0));
    for(int i=1;i<=n;i++) pos[i]=1;
    ST::build(1,n,1);
    int l,r,k;char op;
    while(m--)
    {
        op=getchar();
        while(op!='C'&&op!='Q') op=getchar();
        l=read(),r=read();
        if(op=='C')
        {
            k=read();
            pos[k]=SG::insert(rt,0,1,data(pos[l],pos[r]));
            if(R) SG::rebuild(rt,0,1),R=0;
            ST::update(k,1,n,1);
        }
        else print(ST::query(l,r,1,n,1)),putchar('\n');
    }
    return 0;
}

/*
5 10
C 1 1 1
C 2 1 2
Q 1 2
C 4 4 4
C 5 5 5
Q 4 5
Q 3 3
C 4 2 3
C 4 4 4
Q 3 4
*/

后缀平衡树改天再更啦~

posted @ 2019-04-18 19:24 Owen_codeisking 阅读(...) 评论(...) 编辑 收藏