http://acm.hdu.edu.cn/showproblem.php?pid=3436
题意:初始排列1到N,现在要你实现3种操作:
将x插入到队头去
询问x当前的位置
询问第x个位置上当前是谁.
分析:
下面用SplayTree来实现.不过依然要明白SplayTree提供的是N个房间,第i号房间里放的就是第i个人,各种操作不会变化房间的内容,变得只是房间之间的相对父子关系而已.
SplayTree需要 size,pre,ch 3种信息即可.
首先将1到n建立SPlayTree.
我们将根root节点的右儿子的左儿子位置称为关键位置.
对于top x操作:由于第x个人在x号房间里,先将x号房间旋转到根,删除根,在将最小的节点旋转到根,然后用x号房间替换最小的节点称为根.
对于Query x操作:直接将x+1号房间转到根节点,返回它左子树儿子个数即可.
对于Rank x 操作:直接用Get_Kth即可实现,找到第x+1位置的房间号.
不过这道题的N<=10^8,但是Q<=10^5,所以需要将数据离散化,对于所有top x命令,我们将所有区间离散化,然后依然第i个房间放的是顺序第i个区间,SplayTree的size数组表示节点r为根的树中所有区间包含的整数个数,num数组表示节点r(仅仅r节点)表示的区间所包含的数总数,也就是顺序第r个区间包含的数的总数.
AC代码:
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 using namespace std; 6 const int maxn=200000+100; 7 int N,Q,T; 8 int s[maxn],e[maxn],cnt;//表示区间 9 int p[maxn];//提取出来的单点数 10 char op[maxn][10];//命令 11 int qnum[maxn];//命令参数 12 int bin(int x) 13 { 14 int l=1,r=cnt; 15 while(l<=r) 16 { 17 int mid=(l+r)>>1; 18 if(s[mid]<=x && x<=e[mid]) 19 return mid; 20 else if(x< s[mid]) 21 r=mid-1; 22 else 23 l=mid+1; 24 } 25 return -1; 26 } 27 28 int size[maxn]; 29 int num[maxn]; 30 int pre[maxn]; 31 int ch[maxn][2],root; 32 33 void Treavel(int x) 34 { 35 if(x) 36 { 37 Treavel(ch[x][0]); 38 39 printf("节点 %2d: 左儿子 %2d 右儿子 %2d ",x,ch[x][0],ch[x][1]); 40 printf("size %2d num %2d pre %2d s %2d e %2d ",size[x],num[x],pre[x],s[x],e[x]); 41 42 Treavel(ch[x][1]); 43 } 44 } 45 void DeBug() 46 { 47 printf("root:%d ",root); 48 Treavel(root); 49 } 50 void Push_Up(int r) 51 { 52 size[r] = size[ch[r][0]]+size[ch[r][1]]+num[r]; 53 } 54 void Rotate(int x,int kind) 55 { 56 int y=pre[x]; 57 ch[y][kind^1] = ch[x][kind]; 58 pre[ch[x][kind]] = y; 59 if(pre[y]) 60 ch[pre[y]][ch[pre[y]][1] == y] = x; 61 pre[x]=pre[y]; 62 ch[x][kind]=y; 63 pre[y]=x; 64 Push_Up(y); 65 } 66 67 void Splay(int r,int goal) 68 { 69 while(pre[r]!=goal) 70 { 71 if(pre[pre[r]]==goal) 72 Rotate(r,ch[pre[r]][0]==r); 73 else 74 { 75 int y=pre[r]; 76 int kind=ch[pre[y]][0] == y; 77 if(ch[y][kind] == r) 78 { 79 Rotate(r,kind^1); 80 Rotate(r,kind); 81 } 82 else 83 { 84 Rotate(y,kind); 85 Rotate(r,kind); 86 } 87 } 88 } 89 Push_Up(r); 90 if(goal==0) 91 root=r; 92 } 93 void New_Node(int &r,int fa,int k) 94 { 95 r=k; 96 num[r]=size[r]=e[k]-s[k]+1; 97 pre[r]=fa; 98 ch[r][0]=ch[r][1]=0; 99 } 100 void Build(int &x,int l,int r,int fa) 101 { 102 if(l>r) 103 return; 104 int mid=(l+r)>>1; 105 New_Node(x,fa,mid); 106 Build(ch[x][0],l,mid-1,x); 107 Build(ch[x][1],mid+1,r,x); 108 Push_Up(x); 109 } 110 void init() 111 { 112 root=0; 113 pre[root]=0; 114 ch[root][0]=ch[root][1]=0; 115 size[root]=0; 116 num[root]=0; 117 Build(root,1,cnt,0); 118 } 119 int Get_Min(int r) 120 { 121 while(ch[r][0]) r=ch[r][0]; 122 return r; 123 } 124 125 //删除树根 126 void Delete() 127 { 128 if(ch[root][0]==0 || ch[root][1]==0) 129 { 130 root = ch[root][0]+ch[root][1]; 131 pre[root]=0; 132 return ; 133 } 134 int k=Get_Min(ch[root][1]); 135 Splay(k,root); 136 ch[k][0]=ch[root][0]; 137 pre[ch[root][0]]=k; 138 root=k; 139 pre[k]=0; 140 Push_Up(root); 141 } 142 void Top(int x) 143 { 144 int r=bin(x); 145 Splay(r,0); 146 Delete(); 147 Splay(Get_Min(root),0); 148 ch[r][0]=0; 149 ch[r][1]=root; 150 pre[r]=0; 151 pre[root]=r; 152 root=r; 153 Push_Up(r); 154 } 155 int Query(int x) 156 { 157 int r=bin(x); 158 Splay(r,0); 159 return size[ch[r][0]]+x-s[r]+1; 160 } 161 int Rank(int x) 162 { 163 int r=root; 164 while(1) 165 { 166 //size[r]我之前写成了N,一直WA 167 if(size[ch[r][0]] < x && size[r]-size[ch[r][1]] >= x) 168 return s[r]-1+x-size[ch[r][0]]; 169 else if(x<=size[ch[r][0]]) 170 r=ch[r][0]; 171 else 172 { 173 //这里的顺序千万别写反了,而且size[r]我之前写成了N,一直WA 174 x-=size[r]-size[ch[r][1]]; 175 r=ch[r][1]; 176 } 177 } 178 } 179 180 //和上面那个Rank函数一样的功能,两个二选一,用一个即可 181 int Get_Rank(int r,int k) 182 { 183 int t = size[ch[r][0]]; 184 if(k <= t) 185 return Get_Rank(ch[r][0],k); 186 else if(k <= t + num[r]) 187 return s[r] + k - t - 1; 188 else 189 return Get_Rank(ch[r][1],k-t-num[r]); 190 } 191 192 int main() 193 { 194 scanf("%d",&T); 195 for(int kase=1;kase<=T;kase++) 196 { 197 scanf("%d%d",&N,&Q); 198 199 int t=0; 200 for(int i=1;i<=Q;i++) 201 { 202 scanf("%s%d",op[i],&qnum[i]); 203 if(op[i][0]=='T') 204 p[t++]=qnum[i]; 205 } 206 p[t++]=1; 207 p[t++]=N; 208 sort(p,p+t); 209 t=unique(p,p+t)-p; 210 cnt=0; 211 for(int i=0;i<t;i++) 212 { 213 if(i>0 && p[i]>p[i-1]+1) 214 { 215 cnt++; 216 s[cnt]=p[i-1]+1; 217 e[cnt]=p[i]-1; 218 } 219 cnt++; 220 s[cnt]=e[cnt]=p[i]; 221 } 222 init(); 223 printf("Case %d: ",kase); 224 for(int i=1;i<=Q;i++) 225 { 226 if(i==4) 227 { 228 int x=1; 229 int y=1; 230 } 231 if(op[i][0]=='T') 232 Top(qnum[i]); 233 else if(op[i][0]=='Q') 234 printf("%d ",Query(qnum[i])); 235 else if(op[i][0]=='R') 236 printf("%d ",Rank(qnum[i])); 237 } 238 } 239 return 0; 240 }