http://acm.hdu.edu.cn/showproblem.php?pid=4441
题意:对于一个序列,每次有三种操作
insert pos 表示在pos插入一个数,这个数是最小的正数没有在序列中出现的。而且还要在某个位置插入他的相反数,使得这个序列满足队列的出入顺序(正表示进,负表示出)
remove num 表示在序列中把num以及-num两数去掉
query num 把num与-num之间的数求和输出
这题我本来实在是没有思路,看起来像维护一个线段树,这样求和好办,但是序列的长度是会变的,而且元素的绝对位置是会变的,线段树就无法解决了。
通过这题我才了解了一个新的数据结构:Splay Tree。每个节点不仅要保存元素值,还需要维护以当前节点为根的子树所含的正数个数和负数个数以及从开头到当前元素的序列和。在一棵二叉查找树种如何在第i个元素之前插入一个元素呢?我原先想构造二叉树使得后序遍历为当前序列,这样要在一个元素前插入一个节点,就在以这个节点的左子树的最右端插入就可以了,这样不怕没位置。但问题是,为了提高查找树的效率,无论用AVL Tree 还是 Splay Tree 都要用旋转操作,这一旋转就会破坏这个关系。要是旋转操作保持树的原有性质,就只能用中序:节点的左子树的所有元素都在当前元素的左边,节点的右子树的所有元素都在当前元素的右边。那如何在指定位置插入呢,那只能先断开节点和一个子树的联系,在此之间插入新元素节点再连接起来。
用Splay Tree的好处是SP树可以把一个节点提到树根并保持整棵树的性质,这样在插入、删除以及合并时更加方便,这样可以很快地把树以一个标准分为两个部分,更据偏序关系来操作。由于Splay Tree需要多次旋转,插入删除时也会更改树的结构,所以要注意节点的更新和更新的顺序!
确定当前不在序列中的最小正整数用线段树来维护就好了。这题用了两种数据结构和变异的算法,逻辑复杂,再用类封装,所以代码量比较大,我也调试了许久,问题出来节点更新和些小细节上,不过总算AC了。
1 #include <stdio.h> 2 #include <string.h> 3 #include <stdlib.h> 4 inline int mymin(int a,int b) 5 { 6 if (a==-1) return b; 7 if (b==-1) return a; 8 return a>b?b:a; 9 } 10 struct segtree 11 { 12 #define sbegin 1,100000,1 13 int tree[100001<<2]; 14 segtree(){build(sbegin);} 15 void build(int l,int r,int rt) 16 { 17 if (l==r){tree[rt]=l;return;} 18 int mid=(l+r)>>1; 19 build(l,mid,rt<<1); 20 build(mid+1,r,rt<<1|1); 21 tree[rt]=mymin(tree[rt<<1],tree[rt<<1|1]); 22 } 23 void update(int l,int r,int rt,int p,int op) 24 { 25 if (l==r && l==p){tree[rt]=op; return;} 26 int mid=(l+r)>>1; 27 if (p<=mid) update(l,mid,rt<<1,p,op); 28 if (p>mid) update(mid+1,r,rt<<1|1,p,op); 29 tree[rt]=mymin(tree[rt<<1],tree[rt<<1|1]); 30 } 31 int query(){return tree[1]; } 32 void insert(int p) { update(sbegin,p,-1);} 33 void del(int p){update(sbegin,p,p); } 34 }*myseg; 35 struct spt 36 { 37 38 spt(){root=NULL;} 39 struct node 40 { 41 int data; 42 long long sum; 43 int zs,fs; 44 node *left,*right,*father; 45 node(int d=0,node* a=NULL,node *b=NULL,node *c=NULL):data(d),left(a),right(b),father(c) 46 {sum=data;zs=data>0;fs=data<0;} 47 }*root; 48 void print(node *p) 49 { 50 if (p==NULL) return; 51 print(p->left); 52 printf("[%d] data: %d sum: %I64d zs: %d fs:%d | %4d %4d %4d ",p,p->data,p->sum,p->zs,p->fs,p->father,p->left,p->right); 53 print(p->right); 54 } 55 void update(node *k) 56 { 57 k->sum=k->data; 58 if (k->left) k->sum+=k->left->sum; 59 if (k->right) k->sum+=k->right->sum; 60 k->zs=k->data>0; 61 if (k->left) k->zs+=k->left->zs; 62 if (k->right) k->zs+=k->right->zs; 63 k->fs=k->data<0; 64 if (k->left) k->fs+=k->left->fs; 65 if (k->right) k->fs+=k->right->fs; 66 } 67 void zig(node *k) 68 { 69 node* fa=k->father; 70 fa->left=k->right; 71 if (k->right) k->right->father=fa; 72 k->right=fa; 73 k->father=fa->father; 74 fa->father=k; 75 update(fa); 76 update(k); 77 if (!k->father) return; 78 if (k->father->left==fa) 79 k->father->left=k; 80 else 81 k->father->right=k; 82 update(k->father); 83 } 84 void zag(node *k) 85 { 86 node* fa=k->father; 87 fa->right=k->left; 88 if (k->left) k->left->father=fa; 89 k->left=fa; 90 k->father=fa->father; 91 fa->father=k; 92 update(fa); 93 update(k); 94 if (!k->father) return; 95 if (k->father->left==fa) 96 k->father->left=k; 97 else 98 k->father->right=k; 99 update(k->father); 100 } 101 void splay(node *k,node *&root) 102 { 103 while (k->father) 104 { 105 node *fa=k->father; 106 if (fa->father==NULL) 107 { 108 if (k==fa->left) zig(k); 109 else zag(k); 110 } 111 else 112 { 113 node *gf=fa->father; 114 if (fa==gf->left && k==fa->left) 115 { 116 zig(fa); 117 zig(k); 118 } 119 if (fa==gf->left && k==fa->right) 120 { 121 zag(k); 122 zig(k); 123 } 124 if (fa==gf->right && k==fa->left) 125 { 126 zig(k); 127 zag(k); 128 } 129 if (fa==gf->right && k==fa->right) 130 { 131 zag(fa); 132 zag(k); 133 } 134 } 135 } 136 root=k; 137 } 138 node *findmax(node *&p) 139 { 140 node *t=p; 141 while (t->right) t=t->right; 142 splay(t,p); 143 return t; 144 } 145 node* insert(int data,int tp) 146 { 147 if (root==NULL) {root=new node(data); return root;} 148 if (root->zs+root->fs<tp) 149 { 150 findmax(root); 151 root->right=new node(data); 152 root->right->father=root; 153 update(root); 154 return root->right; 155 } 156 find(tp); 157 node *t=root->left; 158 root->left=new node(data); 159 root->left->father=root; 160 root->left->left=t; 161 if (t) t->father=root->left; 162 update(root->left); 163 update(root); 164 return root->left; 165 } 166 node* insert2(int data,int tp) 167 { 168 if (root->fs<tp) 169 { 170 findmax(root); 171 root->right=new node(data); 172 root->right->father=root; 173 update(root); 174 return root->right; 175 } 176 node *q=__find2(tp,root); 177 if (q) splay(q,root); 178 node *t=root->left; 179 root->left=new node(data); 180 root->left->father=root; 181 root->left->left=t; 182 if (t) t->father=root->left; 183 update(root->left); 184 update(root); 185 return root->left; 186 } 187 node* __find(int tp,node *root) 188 { 189 if (root==NULL) return NULL; 190 int tem=0; 191 if (root->left) tem=root->left->zs+root->left->fs; 192 if (root->left && tp<=tem ) return __find(tp,root->left); 193 if (tem+1==tp) return root; 194 return __find(tp-tem-1,root->right); 195 } 196 node* __find2(int tp,node *root) 197 { 198 if (root==NULL) return NULL; 199 int tem=0; 200 if (root->left) tem=root->left->fs; 201 if (root->left && tp<=tem ) return __find2(tp,root->left); 202 if (tem+(root->data<0)==tp) return root; 203 return __find2(tp-tem-(root->data<0),root->right); 204 } 205 node* find(int tp) 206 { 207 node *q=__find(tp,root); 208 if (q) splay(q,root); 209 return q; 210 } 211 node* join(node *a,node *b) 212 { 213 if (a)a->father=NULL; 214 if (b) b->father=NULL; 215 if (!a || !b) return (node *)((int)a|(int)b); 216 node *t=findmax(a); 217 t->right=b; 218 b->father=t; 219 update(t); 220 return t; 221 } 222 void remove(node *q) 223 { 224 splay(q,root); 225 node *tem=root; 226 root=join(root->left,root->right); 227 delete tem; 228 } 229 void del(node *p) 230 { 231 if (p==NULL) return; 232 del(p->left); 233 del(p->right); 234 delete p; 235 } 236 ~spt(){del(root);} 237 }*mysp; 238 struct pair 239 { 240 spt::node *first,*second; 241 pair(spt::node *a=NULL,spt::node *b=NULL):first(a),second(b){} 242 }path[100002]; 243 void work(char type,int n) 244 { 245 if (type=='i') 246 { 247 int data=myseg->query(); 248 myseg->insert(data); 249 spt::node *a=mysp->insert(data,n+1); 250 mysp->splay(a,mysp->root); 251 int zs=0; 252 if (a->left) zs+=a->left->zs; 253 spt::node *b=mysp->insert2(-data,zs+1); 254 path[data]=pair(a,b); 255 } 256 if (type=='r') 257 { 258 pair t=path[n]; 259 mysp->remove(t.first); 260 mysp->remove(t.second); 261 myseg->del(n); 262 } 263 if (type=='q') 264 { 265 long long ans=0; 266 pair t=path[n]; 267 mysp->splay(t.second,mysp->root); 268 if (mysp->root->left) ans+=mysp->root->left->sum; 269 mysp->splay(t.first,mysp->root); 270 ans-=mysp->root->data; 271 if (mysp->root->left) ans-=mysp->root->left->sum; 272 printf("%I64d ",ans); 273 } 274 } 275 int main() 276 { 277 int n,cas=0; 278 while (~scanf("%d",&n)) 279 { 280 printf("Case #%d: ",++cas); 281 mysp=new spt; 282 myseg=new segtree; 283 char cmd[256]; 284 int t; 285 while (n--) 286 { 287 scanf("%s%d",cmd,&t); 288 work(cmd[0],t); 289 } 290 delete mysp; 291 delete myseg; 292 } 293 }