hdu3436 splaytree树模拟队列+离散化缩点

数据较大,需要先把每个top不会操作到的段缩成一个点,记录其开始和结束的位置,和top能操作到的点一起建立一颗伸展树模拟

然后就是普通的队列模拟操作

/*
不会被top操作到的区间就缩点
通过splay tree模拟出序列,初始序列的第i个缩点对应的树结点也是i
操作top a:找到结点a,将其移到最左边
query a:结点a的左边有多少人
rank a:第a个结点是第几个结点
*/
#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#define maxn 100005
#define L ch[r][0]
#define R ch[r][1]
using namespace std;

int pre[maxn],ch[maxn][2],size[maxn],num[maxn],root,tot;
int s[maxn],e[maxn],cnt; 
void debug();
inline void newnode(int &r,int fa,int k){
    r=k;
    ch[r][0]=ch[r][1]=0;
    pre[r]=fa;
    size[r]=num[r]=e[k]-s[k]+1;
}
inline void pushup(int r){
    size[r]=size[L]+size[R]+num[r];
}
void build(int &x,int l,int r,int fa){
    if(l>r) return;
    int mid=l+r>>1;
    newnode(x,fa,mid);
    build(ch[x][0],l,mid-1,x);
    build(ch[x][1],mid+1,r,x);
    pushup(x);
}
void init(int n){
    root=tot=0;
    size[root]=pre[root]=ch[root][0]=ch[root][1]=0;
    build(root,1,n,0);
}
void Rotate(int x,int kind)
{
    int y = pre[x];
    //pushdown(y);
    //pushdown(x);//先把y的标记下传,在把x的标记下传
    ch[y][!kind] = ch[x][kind];
    pre[ch[x][kind]] = y;
    if(pre[y])
        ch[pre[y]][ch[pre[y]][1]==y] = x;
    pre[x] = pre[y];
    ch[x][kind] = y;
    pre[y] = x;
    pushup(y);
}
//Splay调整,将r结点调整到goal下面
void splay(int r,int goal)
{
    //push_down(r);
    while(pre[r] != goal)
    {
        if(pre[pre[r]] == goal)
            Rotate(r,ch[pre[r]][0]==r);
        else
        {
            int y = pre[r];
            int kind = ch[pre[y]][0]==y;
            if(ch[y][kind] == r)
            {
                Rotate(r,!kind);
                Rotate(r,kind);
            }
            else
            {
                Rotate(y,kind);
                Rotate(r,kind);
            }
        }
    }
    pushup(r);
    if(goal == 0) root = r;
}  
int getmin(int r){while(L) r=L;return r;}   
void del(){
    int t=root;
    if(ch[root][1]){
        root=ch[root][1];
        splay(getmin(root),0);
        ch[root][0]=ch[t][0];
        if(ch[root][0]) pre[ch[root][0]]=root;
    }
    else root=ch[root][0];
    pre[root]=0;
    pushup(root);
}   
int Bin(int x){//二分查找x属于那一段
    int l=1,r=cnt;
    while(l<=r){
        int mid=l+r>>1;
        if(s[mid]<=x && e[mid]>=x) return mid;
        if(x<s[mid]) r=mid-1;
        else l=mid+1;
    }
    return -1;
}void Treavel(int x)
{
    if(x)
    {
        Treavel(ch[x][0]);
        printf("结点:%2d: 左儿子 %2d 右儿子 %2d 父结点 %2d size = %2d  num = %2d s = %2d e = %2d
",x,ch[x][0],ch[x][1],pre[x],size[x],num[x],s[x],e[x]);
        Treavel(ch[x][1]);
    }
}
void debug()
{
    printf("root:%d
",root);
    Treavel(root);
}
void top(int x){//把结点r移到最左边
    int r=Bin(x);
    splay(r,0);
    del();
   
    ch[r][0]=0;
    ch[r][1]=root;
    pre[root]=r;
    root=r;
    pre[root]=0;
    pushup(root);
    //debug();
}
int query(int x){//结点x左边有多少结点
    int r=Bin(x);
    splay(r,0);
    return size[ch[root][0]]+x-s[r]+1;
}
int rankk(int r,int k){//排在第k位的结点
    int t=size[ch[r][0]];
    if(k<=t) return rankk(ch[r][0],k);
    else if(k<=t+num[r]) return s[r]+k-t-1;
    else return rankk(ch[r][1],k-t-num[r]);
}

char op[maxn][10];
int qnum[maxn],p[maxn];

int main(){
    int n,q,T;
    scanf("%d",&T);
    for(int tt=1;tt<=T;tt++){
        scanf("%d%d",&n,&q);
        int t=0;
        for(int i=0;i<q;i++){
            scanf("%s%d",op[i],&qnum[i]);
            if(op[i][0]=='T')
                p[t++]=qnum[i];
        }
        p[t++]=1;
        p[t++]=n;
        sort(p,p+t);
        t=unique(p,p+t)-p;
        cnt=0;
        for(int i=0;i<t;i++){
            if(i>0 && p[i]-p[i-1]>1){
                cnt++;
                s[cnt]=p[i-1]+1;
                e[cnt]=p[i]-1;
            }
            cnt++;
            s[cnt]=p[i];e[cnt]=p[i];
        }
        init(cnt);
      //  debug();
        printf("Case %d:
",tt);
        for(int i=0;i<q;i++){
        //    debug();
            if(op[i][0]=='T') top(qnum[i]);
            else if(op[i][0]=='Q') printf("%d
",query(qnum[i]));
            else printf("%d
",rankk(root,qnum[i]));
           // debug();
        }
    }
    return 0;
}
原文地址:https://www.cnblogs.com/zsben991126/p/10006172.html