数据较大,需要先把每个top不会操作到的段缩成一个点,记录其开始和结束的位置,和top能操作到的点一起建立一颗伸展树模拟
然后就是普通的队列模拟操作
/*不会被top操作到的区间就缩点通过splay tree模拟出序列,初始序列的第i个缩点对应的树结点也是i操作top a:找到结点a,将其移到最左边query a:结点a的左边有多少人rank a:第a个结点是第几个结点*/#include#include #include #include #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 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:\n",tt); for(int i=0;i