洛谷P3850 [TJOI2007]书架
洛谷P3850 [TJOI2007]书架
题目描述
Knuth先生家里有个精致的书架,书架上有N本书,如今他想学到更多的知识,于是又买来了M本不同的新书。现在他要把新买的书依次插入到书架中,他已经把每本书要插入的位置标记好了,并且相应的将它们放好。由于Knuth年龄已大,过几天他已经记不清某些位置上放的到底是什么书了,请问你能帮助他吗?
输入输出格式
输入格式:
输入文件的第一行为整数N,接下来N行分别是书架上依次放着的N本书的书名(书名由不含空格的字符串构成,长度不超过10)。下一行将要输入一个整数M,接下来的M行分别为这本书的书名和要插入的位置。下一行将要输入一个整数Q,接下来共有Q次询问,每行都是一个整数表示询问的位置。(书架上位置的编号从0开始)
输出格式:
输出Q行,每行对应着相应查询位置的书名。
思路:
针对一开始的每一个已经排好的书,正常地建树,节点的权值可以设为该书的编号(其实在这道题里,节点的权值并没有什么意义)
对于新插入的节点,假设该节点插入在k位置,那么先将平衡树的第k个节点伸展到树顶,然后再把平衡树的第k-1个节点伸展到根节点的左子树。此时,很显然第k-1个节点的右子树一定为空,这时候把新来的书插在这个位置。
最后对于每一个询问,直接查第k个节点就行了。
为了防止各种奇怪的问题,我在建树的时候还特意插入了最小节点和最大节点
以下是代码:
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> using namespace std; #define MAXN 1000010 int ch[MAXN][2],val[MAXN],par[MAXN],cnt[MAXN],sizes[MAXN]; char names[MAXN][15]; int i,j,k,m,n,ncnt,root,q; int chk(int x){ return ch[par[x]][1]==x; } void pushup(int x){ sizes[x]=sizes[ch[x][0]]+sizes[ch[x][1]]+cnt[x]; } void rotate(int x){ int y=par[x],z=par[y],k=chk(x),w=ch[x][!k]; ch[y][k]=w,par[w]=y; ch[z][chk(y)]=x,par[x]=z; ch[x][!k]=y,par[y]=x; pushup(y),pushup(x); } void splay(int x,int goal=0){ while(par[x]!=goal){ int y=par[x],z=par[y]; if(z!=goal){ if(chk(x)==chk(y)) rotate(y); else rotate(x); } rotate(x); } if(!goal) root=x; } void find(int v){ if(!root) return; int cur=root; while(val[ch[cur][v>val[cur]]]&&v!=val[cur]){ cur=ch[cur][v>val[cur]]; } splay(cur); } void insert(int v){ int cur=root,p=0; while(cur&&val[cur]!=v){ p=cur; cur=ch[cur][v>val[cur]]; } if(cur){ cnt[cur]++; }else{ cur=++ncnt; if(p) ch[p][v>val[p]]=cur; ch[cur][0]=ch[cur][1]=0; val[cur]=v,par[cur]=p; cnt[cur]=sizes[cur]=1; } splay(cur); } int kth(int k){ int cur=root; while(true){ if(ch[cur][0]&&sizes[ch[cur][0]]>=k){ cur=ch[cur][0]; }else{ if(sizes[ch[cur][0]]+cnt[cur]<k){ k-=sizes[ch[cur][0]]+cnt[cur]; cur=ch[cur][1]; }else{ return cur; } } } } int ranks(int v){ find(v); return sizes[ch[root][0]]+1; } int pre(int v){ find(v); if(val[root]<v) return root; int cur=ch[root][0]; while(ch[cur][1]) cur=ch[cur][1]; return cur; } int succ(int v){ find(v); if(val[root]>v) return root; int cur=ch[root][1]; while(ch[cur][0]) cur=ch[cur][0]; return cur; } void remove(int v){ int last=pre(v),Next=succ(v); splay(last),splay(Next,last); int del=ch[Next][0]; if(cnt[del]>1){ cnt[del]--; splay(del); }else{ ch[Next][0]=0; splay(Next); } } int main(){ ncnt=0; root=0; insert(-1),insert(1000000000); scanf("%d",&n); for(i=1;i<=n;i++) { scanf("%s",names[i]); insert(i); } scanf("%d",&m); for(i=1;i<=m;i++){ scanf("%s%d",names[n+i],&k); k=k+2; int id=kth(k); splay(id); int sid=kth(k-1); splay(sid,id); ch[sid][1]=++ncnt; ch[ncnt][0]=ch[ncnt][1]=0; par[ncnt]=sid; val[ncnt]=k; cnt[ncnt]=sizes[ncnt]=1; pushup(sid),pushup(id); } scanf("%d",&q); for(i=1;i<=q;i++){ scanf("%d",&k); int id=kth(k+2); printf("%s\n",names[id-2]); } return 0; }