题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3436
树状数组做法<猛戳>
Splay tree的经典题目,有删除和移动操作。首先要离散化各个点,而且对于没有区间还要缩点。对于Top操作,先把目标节点删除,然后移到最左端。Query操作,Splay(tar,0),然后直接访问size。对于Rank操作,通过size产找即可。注意,在每次更新后,都要把处理过的节点都要Splay(tar,0)才能保证复杂度为O(log n),因为这样才能方便下次的访问,因为这个TLE了一个下午+一个晚上。。。。Splay()操作太神了。。
1 //STATUS:C++_AC_187MS_4196KB 2 #include <functional> 3 #include <algorithm> 4 #include <iostream> 5 //#include <ext/rope> 6 #include <fstream> 7 #include <sstream> 8 #include <iomanip> 9 #include <numeric> 10 #include <cstring> 11 #include <cassert> 12 #include <cstdio> 13 #include <string> 14 #include <vector> 15 #include <bitset> 16 #include <queue> 17 #include <stack> 18 #include <cmath> 19 #include <ctime> 20 #include <list> 21 #include <set> 22 #include <map> 23 using namespace std; 24 //using namespace __gnu_cxx; 25 //define 26 #define pii pair<int,int> 27 #define mem(a,b) memset(a,b,sizeof(a)) 28 #define lson l,mid,rt<<1 29 #define rson mid+1,r,rt<<1|1 30 #define PI acos(-1.0) 31 //typedef 32 typedef __int64 LL; 33 typedef unsigned __int64 ULL; 34 //const 35 const int N=100010; 36 const int INF=0x3f3f3f3f; 37 const int MOD=100000,STA=8000010; 38 const LL LNF=1LL<<60; 39 const double EPS=1e-8; 40 const double OO=1e15; 41 const int dx[4]={-1,0,1,0}; 42 const int dy[4]={0,1,0,-1}; 43 const int day[13]={0,31,28,31,30,31,30,31,31,30,31,30,31}; 44 //Daily Use ... 45 inline int sign(double x){return (x>EPS)-(x<-EPS);} 46 template<class T> T gcd(T a,T b){return b?gcd(b,a%b):a;} 47 template<class T> T lcm(T a,T b){return a/gcd(a,b)*b;} 48 template<class T> inline T lcm(T a,T b,T d){return a/d*b;} 49 template<class T> inline T Min(T a,T b){return a<b?a:b;} 50 template<class T> inline T Max(T a,T b){return a>b?a:b;} 51 template<class T> inline T Min(T a,T b,T c){return min(min(a, b),c);} 52 template<class T> inline T Max(T a,T b,T c){return max(max(a, b),c);} 53 template<class T> inline T Min(T a,T b,T c,T d){return min(min(a, b),min(c,d));} 54 template<class T> inline T Max(T a,T b,T c,T d){return max(max(a, b),max(c,d));} 55 //End 56 57 #define Key_value ch[ch[root][1]][0] 58 int pre[N<<1],ch[N<<1][2]; //分别表示父结点,键值,左右孩子(0为左孩子,1为右孩子),根结点,结点数量 59 int sz[N<<1],st[N]; //子树规模,内存池 60 int root,tot,top; //根节点,根节点数量,内存池容量 61 //题目特定数据 62 int op[N],cnt[N<<1],s[N<<1],e[N<<1]; 63 int num[N],p[N]; 64 int T,n,m,up; 65 //debug部分copy from hh 66 void Treaval(int x) { 67 if(x) { 68 Treaval(ch[x][0]); 69 printf("结点%2d:左儿子 %2d 右儿子 %2d 父结点 %2d size = %2d\n",x,ch[x][0],ch[x][1],pre[x],sz[x]); 70 Treaval(ch[x][1]); 71 } 72 } 73 void debug() {printf("%d\n",root);Treaval(root);} 74 //以上Debug 75 //新建一个结点 76 void NewNode(int &x,int fa,int k,int size) 77 { 78 // if(top)x=st[--top]; 79 // else x=++tot; 80 x=k; 81 pre[x]=fa; 82 sz[x]=cnt[x]=size; 83 ch[x][0]=ch[x][1]=0; //左右孩子为空 84 } 85 86 inline void Push_Up(int x) 87 { 88 sz[x]=sz[ch[x][0]]+sz[ch[x][1]]+cnt[x]; 89 } 90 //旋转,kind为1为右旋,kind为0为左旋 91 void Rotate(int x,int kind) 92 { 93 int y=pre[x],z=pre[y]; 94 //类似SBT,要把其中一个分支先给父节点 95 ch[y][!kind]=ch[x][kind]; 96 pre[ch[x][kind]]=y; 97 //如果父节点不是根结点,则要和父节点的父节点连接起来 98 if(z)ch[z][ch[z][1]==y]=x; 99 pre[x]=z; 100 ch[x][kind]=y; 101 pre[y]=x; 102 Push_Up(y); //维护y结点,不要维护x节点,x节点会再次Push_Down,最后维护一下x节点即可 103 } 104 //Splay调整,将根为r的子树调整为goal 105 void Splay(int x,int goal) 106 { 107 int y,z,kind; 108 while(pre[x]!=goal){ 109 //父节点即是目标位置,goal为0表示,父节点就是根结点 110 y=pre[x]; 111 if(pre[y]==goal){ 112 Rotate(x,ch[y][0]==x); 113 } 114 else { 115 kind=ch[pre[y]][0]==y; 116 //两个方向不同,则先左旋再右旋 117 if(ch[y][kind]==x){ 118 Rotate(x,!kind); 119 Rotate(x,kind); 120 } 121 //两个方向相同,相同方向连续两次 122 else { 123 Rotate(y,kind); 124 Rotate(x,kind); 125 } 126 } 127 } 128 //更新根结点 129 Push_Up(x); 130 if(goal==0)root=x; 131 } 132 133 int Get_Min(int x) 134 { 135 while(ch[x][0])x=ch[x][0]; 136 return x; 137 } 138 //建树,中间结点先建立,然后分别对区间两端在左右子树建立 139 void BuildTree(int &x,int l,int r,int fa) 140 { 141 if(l>r)return; 142 int mid=(l+r)>>1; 143 NewNode(x,fa,mid,e[mid]-s[mid]+1); 144 BuildTree(ch[x][0],l,mid-1,x); 145 BuildTree(ch[x][1],mid+1,r,x); 146 Push_Up(x); 147 } 148 149 void Init() 150 { 151 root=tot=top=0; 152 ch[0][0]=ch[0][1]=pre[0]=sz[0]=cnt[0]=0; 153 154 int i,t,k; 155 char ss[8]; 156 p[0]=0,t=1; 157 for(i=1;i<=m;i++){ 158 scanf("%s%d",ss,&num[i]); 159 op[i]=ss[0]=='T'?1:ss[0]=='Q'?2:0; 160 if(op[i])p[t++]=num[i]; 161 } 162 sort(p,p+t); 163 for(k=1,i=2;i<t;i++) 164 if(p[i]!=p[k])p[++k]=p[i]; 165 for(i=1,up=0;i<=k;i++){ 166 if(p[i]-p[i-1]>1){ 167 s[++up]=p[i-1]+1; 168 e[up]=p[i]-1; 169 } 170 s[++up]=p[i]; 171 e[up]=p[i]; 172 } 173 if(e[up]!=n){ 174 ++up; 175 s[up]=e[up-1]+1; 176 e[up]=n; 177 } 178 BuildTree(root,1,up,0); 179 } 180 //删除编号为x的节点 181 void Delete(int x) 182 { 183 int y=pre[x],s; 184 if(sz[x]==cnt[x]){ 185 ch[y][ch[y][1]==x]=0; 186 s=y; 187 } 188 else if(ch[x][0]==0 || ch[x][1]==0){ 189 s=ch[x][0]?ch[x][0]:ch[x][1]; 190 if(y)ch[y][ch[y][1]==x]=s; 191 pre[s]=y; 192 } 193 else { 194 s=Get_Min(ch[x][1]); 195 Splay(s,x); 196 if(ch[x][0]){ 197 ch[s][0]=ch[x][0]; 198 pre[ch[x][0]]=s; 199 } 200 pre[s]=y; 201 if(y)ch[y][ch[y][1]==x]=s; 202 } 203 if(y==0)root=s; 204 Splay(s,0); 205 } 206 207 void Top(int tar) 208 { 209 if(sz[root]==cnt[root])return; 210 Delete(tar); 211 int x=Get_Min(root); 212 ch[x][0]=tar; 213 pre[tar]=x; 214 sz[tar]=cnt[tar]; 215 ch[tar][0]=ch[tar][1]=0; 216 Splay(tar,0); 217 } 218 219 int Query(int tar) 220 { 221 Splay(tar,0); 222 return sz[ch[root][0]]+cnt[tar]; 223 } 224 225 int Rank(int k) 226 { 227 int x=root; 228 while(1){ 229 if(k>sz[ch[x][0]] && k<=sz[ch[x][0]]+cnt[x]){ 230 k-=sz[ch[x][0]]; 231 break; 232 } 233 else if(k<=sz[ch[x][0]]) 234 x=ch[x][0]; 235 else { 236 k-=sz[ch[x][0]]+cnt[x]; 237 x=ch[x][1]; 238 } 239 } 240 return s[x]+k-1; 241 } 242 243 int binary(int l,int r,int tar) 244 { 245 int mid; 246 while(l<r){ 247 mid=(l+r)>>1; 248 if(e[mid]<tar)l=mid+1; 249 else if(s[mid]>tar)r=mid; 250 else return mid; 251 } 252 return -1; 253 } 254 255 int main() 256 { 257 // freopen("in.txt","r",stdin); 258 int i,j,ca=1,tar; 259 scanf("%d",&T); 260 while(T--) 261 { 262 scanf("%d%d",&n,&m); 263 Init(); 264 printf("Case %d:\n",ca++); 265 for(i=1;i<=m;i++){ 266 if(op[i]){ 267 tar=binary(1,up+1,num[i]); 268 if(op[i]==1)Top(tar); 269 else printf("%d\n",Query(tar)); 270 } 271 else printf("%d\n",Rank(num[i])); 272 } 273 } 274 return 0; 275 }