洛谷P3960 列队 splay

题目链接

https://www.luogu.org/problemnew/show/P3960

题解

观察到向左看齐和向前看齐真正影响的是当前行第y列和当前行的最后一个人,于是每行除最后一个建一个splay,最后一列单独建一个splay。
对于每次操作,删除第x个splay树的第y个,将最后一列的第x个(即第x行最后一列)加入第x个splay树的末尾,再将删除的那个节点加入最后一列的splay树的末尾。

代码

// luogu-judger-enable-o2
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=3e6+10;
typedef long long ll;
int n,m,q;
int fa[maxn],ch[maxn][2],cnt;
ll L[maxn],R[maxn],size[maxn];
int read(){
    int x=0,f=1;char ch=getchar();
    while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
    while(isdigit(ch)){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}
struct Splay{
    int root;
    int newnode(ll l,ll r){
        ++cnt;
        fa[cnt]=ch[cnt][0]=ch[cnt][1]=0;
        size[cnt]=r-l+1;
        R[cnt]=r;L[cnt]=l;
        return cnt;
    }
    void build(ll l,ll r){
        root=newnode(l,r);
    }
    void update(int x){ size[x]=size[ch[x][0]]+size[ch[x][1]]+R[x]-L[x]+1;}
    void rotate(int x){
        int f1=fa[x],f2=fa[f1];
        int s1=ch[f1][1]==x,s2=ch[f2][1]==f1;
        ch[f2][s2]=x;
        fa[x]=f2;
        ch[f1][s1]=ch[x][s1^1];
        fa[ch[x][s1^1]]=f1;
        ch[x][s1^1]=f1;
        fa[f1]=x;
        update(f1);update(x);
    }
    void splay(int x){
        while(fa[x]!=0){
            int f1=fa[x],f2=fa[f1];
            if(f2!=0)
                (ch[f1][1]==x)^(ch[f2][1]==f1)?rotate(x):rotate(f1);
            rotate(x);
        }
        root=x;
    }
    int splitnode(int x,ll k){
        k+=L[x];
        int u=newnode(k,R[x]);
        R[x]=k-1;
        if(ch[x][1]==0){
            ch[x][1]=u;
            fa[u]=x;
        }
        else{
            int now=ch[x][1];
            while(ch[now][0])now=ch[now][0];
            ch[now][0]=u;
            fa[u]=now;
            while(now!=x)update(now),now=fa[now];
        }
        splay(u);
        return u;

    }
    ll kth(ll k){
        int u=root;
        while(7){
            int x=ch[u][0];
            if(size[x]>=k)u=ch[u][0];
            else{
                k-=size[x];
                if(k<=R[u]-L[u]+1){
                    if(k!=R[u]-L[u]+1)splitnode(u,k);
                    if(k!=1)u=splitnode(u,k-1);
                    break;
                }
                else{
                    k-=R[u]-L[u]+1;
                    u=ch[u][1];
                }
            }
        }
        splay(u);
        fa[ch[u][0]]=fa[ch[u][1]]=0;
        if(!ch[u][0]) root=ch[u][1];
        else{
            int x=ch[u][0];
            while(ch[x][1])x=ch[x][1];
            splay(x);
            ch[x][1]=ch[u][1];
            root=fa[ch[x][1]]=x;
            update(x);
        }
        return L[u];
    }
    void insert(ll x){
        int y=newnode(x,x);
        if(!root) root=y;
        else{
            int u=root;
            while(ch[u][1])u=ch[u][1];
            splay(u);
            ch[u][1]=y;
            fa[y]=u;
            update(u);
        }
    }
}T[maxn];
int main(){
    n=read();m=read();q=read();
    for(ll i=1;i<=n;i++)T[i].build((i-1)*m+1,i*m-1);
    T[0].build(m,m);
    for(ll i=2;i<=n;i++)T[0].insert(i*m);
    while(q--){
        int x=read(),y=read();
        T[x].insert(T[0].kth(x));
        ll ans=T[x].kth(y);
        printf("%lld
",ans);
        T[0].insert(ans);
    }
}
原文地址:https://www.cnblogs.com/Nan-Cheng/p/9764265.html