loj#2212. "SCOI2014" Uncle Fang's OJ (splay)

topic here

practice

Fantastic splay...   >w<

Putting it in the first/last position can obviously be converted into, delete it and insert it at the head/tail.

You can refer to the practice of noip2017 D2T3, and replace the actual ranking with "discrete ranking", that is, replace 1~n with a non-consecutive sequence. Set one mi/mx, put it in the first place to set its ranking --mi, and put it in the last place to set it ++mx.

Second, use map to save the discrete ranking of the person numbered x, and use splay to maintain this ordered sequence with ranking as the key. due to n 10 8 , it is not possible to insert all the numbers into the splay, so you can consider inserting an interval, which means that the numbers in this interval have not been modified. If a certain number in the interval is modified, delete the node where the interval is located and insert two new intervals.

Note the difference between discrete ranking and actual ranking.

At this time siz[x], it represents the subtree of the actual ranking size, that is to say, the value of a node sizeis r-l+1. At this time, data[x]represents the id whose ranking is the left endpoint of the interval. In particular, when l = r directly indicates that the ranking is l id of the person.

So when finding rk, you can find the splay node corresponding to the discrete rk of this number, and you can easily calculate the real rk. See the code for details.

code

=> The recursive version is really neat and concise qwq
=> Pay attention to the array size! Since it will not only be split into two new segments for insertion, but also a new segment will be added (when it is placed at the head/tail), so it needs to open 4 times the space.

#include<bits/stdc++.h>
#define rep(i,x,y) for (int i=(x); i<=(y); i++)
#define ll long long
#define ld long double
#define inf 1000000000
using namespace std;
ll read(){
    char ch=getchar(); ll x=0; int op=1;
    for (; !isdigit(ch); ch=getchar()) if (ch=='-') op=-1;
    for (; isdigit(ch); ch=getchar()) x=(x<<1)+(x<<3)+ch-'0';
    return x*op;
}
#define N 400005
int n,m,ans,mx,mi,rt,tot,L[N],R[N],data[N],ch[N][2],fa[N],siz[N]; map<int,int> Mp;
void up(int x){ siz[x]=siz[ch[x][0]]+siz[ch[x][1]]+R[x]-L[x]+1; }
void rot(int x){
    int y=fa[x],z=fa[y],f=ch[y][1]==x;
    ch[y][f]=ch[x][f^1]; if (ch[x][f^1]) fa[ch[x][f^1]]=y;
    fa[x]=z; if (z) ch[z][ch[z][1]==y]=x;
    fa[y]=x; ch[x][f^1]=y; up(y); up(x);
}
void splay(int x,int tp){
    while (fa[x]!=tp){
        int y=fa[x],z=fa[y];
        if (z!=tp) rot((ch[y][0]==x)==(ch[z][0]==y)?y:x);
        rot(x);
    }
    if (!tp) rt=x;
}
void ins(int &x,int l,int r,int key,int pr){
    if (!x){
        x=++tot;
        ch[x][0]=ch[x][1]=0; fa[x]=pr;
        L[x]=l,R[x]=r,data[x]=key; siz[x]=r-l+1;//data存的是区间左端点的编号
        splay(x,0);
        return;
    }
    ins(ch[x][r>=L[x]],l,r,key,x);
}
int find(int x,int k){//查询离散排名为k的所在的节点
    if (L[x]<=k && k<=R[x]) return x;
    else return find(ch[x][k>R[x]],k);
}
int getkth(int x,int k){//查询实际排名为k的人的编号
    if (k>siz[ch[x][0]] && k<=siz[ch[x][0]]+R[x]-L[x]+1){
        if (L[x]==R[x]) return data[x];
        else return L[x]+k-siz[ch[x][0]]-1;
    }
    if (k<=siz[ch[x][0]]) return getkth(ch[x][0],k);
    else return getkth(ch[x][1],k-(siz[ch[x][0]]+R[x]-L[x]+1));
}
void del(int x,int k){//将x节点中删除k这个排名,并分成两个区间插入
    if (!ch[x][0]) rt=ch[x][1],fa[rt]=0; else{
        int y=ch[x][0];
        while (ch[y][1]) y=ch[y][1];//x前驱
        splay(y,x);//此时y没有右子树
        rt=y,fa[rt]=0;
        if (ch[x][1]) ch[y][1]=ch[x][1],fa[ch[x][1]]=y;
        up(rt);
    }
    if (L[x]<=k-1) ins(rt,L[x],k-1,L[x],0);
    if (k+1<=R[x]) ins(rt,k+1,R[x],k+1,0);
}
int main(){
    n=read(),m=read(); ans=0; mx=n,mi=0;//0表示没有修改过
    ins(rt,1,n,1,0);
    while (m--){
        int opt=read(),x=read()-ans,y,rk,tmp,now,nans;
        if (opt==4){ printf("%d\n",ans=getkth(rt,x)); continue; }
        rk=Mp[x]; if (!rk) rk=x; //x的离散排名
        tmp=find(rt,rk); splay(tmp,0);
        printf("%d\n",nans=siz[ch[tmp][0]]+rk-L[tmp]+1);
        del(tmp,rk);
        if (opt==1){
            y=read()-ans; ins(rt,rk,rk,y,0);
            Mp[y]=rk; Mp[x]=0;
        } else{
            Mp[x]=now=opt==2?--mi:++mx;
            ins(rt,now,now,x,0);
        }
        ans=nans;
    }
    return 0;
}

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=326041056&siteId=291194637