【BZOJ3217】ALOEXT-暴力重构线段树-替罪羊树-Trie树-树套树-10k大代码(+数据生成器)
Problem ALOEXT
题目大意
给出一个数据结构维护一个数列,要求支持以下操作:
- 向数列中某个位置插入一个数
- 将数列中某个位置的数删除
- 将数列中某个位置的数换成另外一个数
- 查询一段区间内的次大值与这段区间内整数的异或最大值
要求强制在线。
Solution
看到这个题目以后我们脑子里弹出了许许多多种数据结构。
首先我们看到维护一个数列支持区间查找删除操作不就是线段树嘛!删除操作只用加个tag就行了嘛!
但是这个插入怎么办呢??
然后我们就想到了暴力插入,插入一次就将每一个叶子节点作为非叶子节点,再用右儿子储存原点的数据,左儿子储存插入点的数据。
这样我们只要维护一下每一个点的子树中叶子节点也就是信息存储节点的个数就可以实现$O(\log n)$操作了。
接着我们对于每一个节点开两个变量,存储次大值和最大值,就可以$O(\log n)$查询出次大值。
接下来就是异或最大值了。
在数据结构上的异或问题,Trie树自然就出现在我们眼前了。
我们对于每一个点建一个Trie数,由高位到低位存储某数的二进制序列,这样可以log跑出若干个数的异或最大值。
哈哈哈哈!快解决了.....个毛线啊。
对于一个区间[l,r],我们要用至多log n个线段树上的点来表示它。
于是我们就需要对于这log n个点,一起跑异或最大值。开一个数组记录每棵树跑到的位置,每跑一次循环一下,更新数组,然后就这么多棵Trie树一起往下跑。
这样一次查找操作的时间复杂度为$O(\log n \times \log sizenum)$
非常好,这道题我们到此就解决了...才怪。
我们发现如果用线段树实现插入的话最坏情况会搞出一个链卡掉算法。
怎么办呢。想让一棵树平衡是树结构中永恒的话题。
打暴力呗。直接用替罪羊树的暴力重构思想。
每次插入操作以后我们判断到根链上的每一棵子数平衡系数是否低于alpha。
如果低于的话就选取来拍扁重建一下就好了。pia~树变扁了然后从中间拎起来,重建一下。
好了这道题到此就真的做完了........吗?
没有。我们还要考虑空间复杂度,自己计算一下就知道,若是这样的话会MLE的。
所以我们要分别写两个内存池,给Trie数&&线段(替罪羊)存点。
注意
- 输入数据强制在线同时编号要从第零位开始,也就是对于坐标要全都加一
- 插入删除更新的时候不能每次都merge
- 内存池写的时候一定要注意初始化
- 数列中的数可能出现0的情况,所以点值的初始化不能为0
- 各种判断要严谨地写好
- 特判删除节点,对于每个节点维护died值,表示该子数中有多少个被删除的节点
- 判断是否平衡的时候要加上died值
- 重建时真正删除被打标记删除的节点
- 各种细节一定要处理好!!!!!!!
吐槽
本题当然要槽坏出题人啊。
今年三月开始写的这道题,在集训尾声的时候刚开始写。当时刚学替罪羊,打了一个单纯的替罪羊,没有用叶子节点维护值。
然后我当然就被玩坏了啊。这道题要是那种写法的话特判要多到上天吧。
新的一轮集训,在自己的电脑上看到了这份代码,然后突然想起来这道题还没有a掉。
严谨分析了做法以后,发现那样是不行的,于是
#第一次重写#
重写的时候简直是个傻逼那样。每个点的size值存的是该子树除该点外的信息值。写完了很高兴,跑样例才发现自己忘记打find函数了。。。
打到一半放弃了,因为这样特判也是多到上天了。一个小函数得打100+。为此差点想扇死自己。
#第二次重写#
第二次重写发奋图强立志写出最短的该题代码。强势缩行,写完代码以后只有210行。
当时特别高兴啊。一开始调试就高兴不起来了。
缩行后的代码调试起来简直就跟调一个铁块一样。于是改了很多松散的代码。
因为+1,一天都没看懂样例。后来在一个风雨交加的晚上终于看懂了。
调过样例以后交上去直接re。
超级恐怖啊。一度差点弃坑了。
后来还是强忍着弃坑的冲动写了数据生成器。
一千以内的数据完全跑不出错误啊。
于是手调10w的数据。真の手动二分啊。。。
手动二分还好,为什么我的Trie树会有环啊!!!
调完了又有指向自己的边。。。
就是mmp[memory Pool]的锅!mmpmmpmmp
历经千辛万苦终于re掉了。弃坑。垃圾题目。
其实是我忘记删文件读写了。加上终于A了。
210行调完以后变成了327行。
===吐槽完毕===
Datamaker
可以调整生成出全是insert的数据。
1 #include <iostream> 2 #include <cstdio> 3 #include <ctime> 4 #define MAXN 100000 5 #define MAXM 100000 6 #define MAXS 1000000 7 using namespace std; 8 int main(){ 9 freopen("aloext.in","w",stdout); 10 srand(time(NULL)); 11 int n=rand()%(MAXN-2)+2; 12 n=99999; 13 printf("%d %d\n",n,MAXM); 14 for(int i=1;i<=n;i++) 15 printf("%d ",rand()%MAXS); 16 printf("\n"); 17 for(int i=1;i<=MAXM;i++){ 18 int rnd_tsk=rand()%4; 19 if(rnd_tsk==1&&n==2)rnd_tsk++; 20 if(rnd_tsk==0){ 21 printf("I %d %d\n",rand()%n,rand()%MAXS); 22 n++; 23 }else if(rnd_tsk==1){ 24 printf("D %d\n",rand()%n); 25 n--; 26 }else if(rnd_tsk==2){ 27 int l=rand()%(n-1); 28 printf("F %d %d\n",l,l+rand()%(n-l-1)+1); 29 }else if(rnd_tsk==3){ 30 printf("C %d %d\n",rand()%n,rand()%MAXS); 31 } 32 } 33 }
AC Code
注释和语句后有斜杠的都是可以删除的语句。
1 #include <iostream> 2 #include <cstdio> 3 #define MOD 1048576 4 #define alpha 0.60 5 using namespace std; 6 int sgt_root,n,m,x,y,l,r,p,retmp,find_mmax,find_cmax; 7 int trie_mmp_tot=0,trie_tot=0,sgt_tot=0,sbt=0,lsta=0; 8 int sgt_mmp,mmp[10000010],tmmp[40000010],find_pool_tot=0; 9 int ansnow[1000],fpnow[1000],find_pool[1000]; 10 char ch[2]; 11 struct TrieTree{ 12 int lc,rc,val; 13 bool isrt;// 14 }tr[40000010]; 15 struct ScapeGoatTree{ 16 int lc,rc,size,rt,val,mmax,cmax,died; 17 inline void init(){ 18 lc=0,rc=0,size=0,rt=0,val=-1,mmax=0,cmax=0,died=0; 19 } 20 }a[10000010]; 21 struct RebuildStruct{ 22 int val,rt; 23 }rbd[500010]; 24 int trie_newnode(){ 25 int ret=(trie_mmp_tot==0)?++trie_tot:tmmp[trie_mmp_tot--]; 26 tr[ret].lc=tr[ret].rc=tr[ret].val=0; 27 tr[ret].isrt=0;// 28 return ret; 29 } 30 void trie_delete(int &now){ 31 if(now==0)return; 32 tmmp[++trie_mmp_tot]=now; 33 if(tr[now].lc!=0)trie_delete(tr[now].lc); 34 if(tr[now].rc!=0)trie_delete(tr[now].rc); 35 now=0; 36 } 37 //int dep=0; 38 int trie_merge(int nnow,int xnow,int ynow){ 39 // ++dep; 40 tr[nnow].val=tr[xnow].val+tr[ynow].val; 41 if(tr[xnow].lc||tr[ynow].lc) 42 tr[nnow].lc=trie_merge(trie_newnode(),tr[xnow].lc,tr[ynow].lc); 43 if(tr[xnow].rc||tr[ynow].rc) 44 tr[nnow].rc=trie_merge(trie_newnode(),tr[xnow].rc,tr[ynow].rc); 45 // --dep; 46 return nnow; 47 } 48 int trie_make(int now,int x){ 49 int trie_temper[21],ret=now; 50 for(int i=20;i>=1;i--)trie_temper[i]=(x>>(i-1))&1; 51 for(int i=20;i>=1;i--){ 52 tr[now].val++; 53 if(trie_temper[i]) 54 tr[now].rc=trie_newnode(),now=tr[now].rc; 55 else tr[now].lc=trie_newnode(),now=tr[now].lc; 56 } 57 tr[now].val++; 58 return ret; 59 } 60 void trie_add(int now,int x){ 61 int trie_temper[21]; 62 for(int i=20;i>=1;i--)trie_temper[i]=(x>>(i-1))&1; 63 for(int i=20;i>=1;i--){ 64 tr[now].val++; 65 if(trie_temper[i]){ 66 if(!tr[now].rc)tr[now].rc=trie_newnode(); 67 now=tr[now].rc; 68 }else{ 69 if(!tr[now].lc)tr[now].lc=trie_newnode(); 70 now=tr[now].lc; 71 } 72 } 73 tr[now].val++; 74 } 75 bool trie_minus(int now,int x){ 76 int trie_temper[21]; 77 for(int i=20;i>=1;i--)trie_temper[i]=(x>>(i-1))&1; 78 if(tr[now].val==1){ 79 trie_delete(now); 80 return 1; 81 }else for(int i=20;i>=1;i--){ 82 tr[now].val--; 83 if(trie_temper[i]){ 84 if(tr[tr[now].rc].val==1){ 85 trie_delete(tr[now].rc); 86 return 0; 87 } 88 now=tr[now].rc; 89 } 90 else{ 91 if(tr[tr[now].lc].val==1){ 92 trie_delete(tr[now].lc); 93 return 0; 94 } 95 now=tr[now].lc; 96 } 97 } 98 tr[now].val--; 99 return 0; 100 } 101 int sgt_newnode(){ 102 int ret=(sgt_mmp==0)?++sgt_tot:mmp[sgt_mmp--]; 103 a[ret].init(); 104 return ret; 105 } 106 int sgt_insert(int now,int x,int p){ 107 if(a[now].rc==0&&a[now].lc==0){ 108 a[a[now].rc=sgt_newnode()]=a[now]; 109 a[a[now].lc=sgt_newnode()].val=x; 110 a[a[now].lc].size++;a[a[now].lc].mmax=x; 111 a[a[now].rc].rc=0; 112 a[a[now].lc].rt=trie_make(trie_newnode(),x); 113 tr[a[a[now].lc].rt].isrt=1;// 114 a[now].size=a[a[now].rc].size+1;a[now].val=-1; 115 a[now].died=a[a[now].lc].died+a[a[now].rc].died; 116 a[now].rt=trie_merge(trie_newnode(),a[a[now].lc].rt,a[a[now].rc].rt); 117 // tr[a[now].rt].isrt=1;// 118 if(a[a[now].lc].val>a[a[now].rc].val) 119 a[now].mmax=a[a[now].lc].val, 120 a[now].cmax=a[a[now].rc].val; 121 else a[now].mmax=a[a[now].rc].val, 122 a[now].cmax=a[a[now].lc].val; 123 return 0; 124 } 125 if((a[a[now].lc].size)>=p)retmp=sgt_insert(a[now].lc,x,p); 126 else retmp=sgt_insert(a[now].rc,x,p-a[a[now].lc].size); 127 if(a[a[now].lc].mmax>a[a[now].rc].mmax) 128 a[now].mmax=a[a[now].lc].mmax, 129 a[now].cmax=max(a[a[now].rc].mmax,a[a[now].lc].cmax); 130 else a[now].mmax=a[a[now].rc].mmax, 131 a[now].cmax=max(a[a[now].lc].mmax,a[a[now].rc].cmax); 132 a[now].died=a[a[now].lc].died+a[a[now].rc].died; 133 trie_add(a[now].rt,x); 134 // trie_delete(a[now].rt); 135 // a[now].rt=trie_merge(trie_newnode(),a[a[now].lc].rt,a[a[now].rc].rt); 136 a[now].size=a[a[now].lc].size+a[a[now].rc].size; 137 if(alpha*(a[a[now].lc].size+a[a[now].lc].died)>= 138 (a[a[now].rc].size+a[a[now].rc].died)|| 139 alpha*(a[a[now].rc].size+a[a[now].rc].died)>= 140 (a[a[now].lc].size+a[a[now].lc].died))return now; 141 else return retmp; 142 } 143 int sgt_rebuild(int now,int l,int r){ 144 if(l==r){ 145 a[now].val=rbd[l].val; 146 a[now].rt=rbd[l].rt; 147 a[now].mmax=a[now].val; 148 a[now].size=1; 149 return 1; 150 }else{ 151 int mid=(l+r)>>1; 152 a[now].size=sgt_rebuild(a[now].lc=sgt_newnode(),l,mid)+ 153 sgt_rebuild(a[now].rc=sgt_newnode(),mid+1,r); 154 // tr[a[now].rt].isrt=0;// 155 trie_delete(a[now].rt); 156 a[now].rt=trie_merge(trie_newnode(),a[a[now].lc].rt,a[a[now].rc].rt); 157 // tr[a[now].rt].isrt=1;// 158 if(a[a[now].lc].mmax>a[a[now].rc].mmax) 159 a[now].mmax=a[a[now].lc].mmax, 160 a[now].cmax=max(a[a[now].rc].mmax,a[a[now].lc].cmax); 161 else a[now].mmax=a[a[now].rc].mmax, 162 a[now].cmax=max(a[a[now].lc].mmax,a[a[now].rc].cmax); 163 return a[now].size; 164 } 165 } 166 int sgt_delete(int p,int now){ 167 int ret; 168 if(p==1&&a[now].val!=-1){ 169 // tr[a[now].rt].isrt=0;// 170 trie_delete(a[now].rt); 171 ret=a[now].val; 172 a[now].init(); 173 a[now].died=1; 174 return ret; 175 } 176 if((a[a[now].lc].size)>=p)ret=sgt_delete(p,a[now].lc); 177 else ret=sgt_delete(p-a[a[now].lc].size,a[now].rc); 178 if(trie_minus(a[now].rt,ret))a[now].rt=0; 179 // tr[a[now].rt].isrt=1;// 180 // trie_delete(a[now].rt); 181 // a[now].rt=trie_merge(trie_newnode(),a[a[now].lc].rt,a[a[now].rc].rt); 182 a[now].died++;a[now].size--; 183 if(a[a[now].lc].mmax>a[a[now].rc].mmax) 184 a[now].mmax=a[a[now].lc].mmax, 185 a[now].cmax=max(a[a[now].rc].mmax,a[a[now].lc].cmax); 186 else a[now].mmax=a[a[now].rc].mmax, 187 a[now].cmax=max(a[a[now].lc].mmax,a[a[now].rc].cmax); 188 return ret; 189 } 190 void dfs_breakdown(int x){ 191 if(a[x].lc!=0)dfs_breakdown(a[x].lc); 192 if(a[x].val!=-1){ 193 rbd[++sbt].rt=a[x].rt; 194 rbd[sbt].val=a[x].val; 195 mmp[++sgt_mmp]=x; 196 a[x].init(); 197 return; 198 } 199 if(a[x].rc!=0)dfs_breakdown(a[x].rc); 200 // tr[a[x].rt].isrt=0;// 201 trie_delete(a[x].rt); 202 mmp[++sgt_mmp]=x; 203 a[x].init(); 204 return; 205 } 206 void sgt_breakdown(int x){ 207 if(x==0)return; 208 sbt=0; 209 dfs_breakdown(a[x].lc); 210 dfs_breakdown(a[x].rc); 211 mmp[++sgt_mmp]=x; 212 // tr[a[x].rt].isrt=0;// 213 trie_delete(a[x].rt); 214 x=sgt_newnode(); 215 a[x].size=sgt_rebuild((a[x].lc=sgt_newnode()),1,sbt>>1)+ 216 sgt_rebuild((a[x].rc=sgt_newnode()),(sbt>>1)+1,sbt); 217 a[x].rt=trie_merge(trie_newnode(),a[a[x].lc].rt,a[a[x].rc].rt); 218 // tr[a[x].rt].isrt=1;// 219 if(a[a[x].lc].mmax>a[a[x].rc].mmax) 220 a[x].mmax=a[a[x].lc].mmax, 221 a[x].cmax=max(a[a[x].rc].mmax,a[a[x].lc].cmax); 222 else a[x].mmax=a[a[x].rc].mmax, 223 a[x].cmax=max(a[a[x].lc].mmax,a[a[x].rc].cmax); 224 a[x].died=a[a[x].lc].died+a[a[x].rc].died; 225 } 226 int sgt_change(int p,int now,int x){ 227 int ret; 228 if(p==1&&a[now].val!=-1){ 229 // tr[a[now].rt].isrt=0;// 230 trie_delete(a[now].rt); 231 a[now].rt=trie_make(trie_newnode(),x); 232 // tr[a[now].rt].isrt=1;// 233 ret=a[now].val; 234 a[now].val=x; 235 a[now].mmax=x; 236 return ret; 237 } 238 if((a[a[now].lc].size)>=p)ret=sgt_change(p,a[now].lc,x); 239 else ret=sgt_change(p-a[a[now].lc].size,a[now].rc,x); 240 if(trie_minus(a[now].rt,ret)){ 241 a[now].rt=trie_make(trie_newnode(),x); 242 }else trie_add(a[now].rt,x); 243 // trie_delete(a[now].rt); 244 // a[now].rt=trie_merge(trie_newnode(),a[a[now].lc].rt,a[a[now].rc].rt); 245 if(a[a[now].lc].mmax>a[a[now].rc].mmax) 246 a[now].mmax=a[a[now].lc].mmax, 247 a[now].cmax=max(a[a[now].rc].mmax,a[a[now].lc].cmax); 248 else a[now].mmax=a[a[now].rc] .mmax, 249 a[now].cmax=max(a[a[now].lc].mmax,a[a[now].rc].cmax); 250 return ret; 251 } 252 void sgt_find(int now,int l,int r){ 253 if(l==1&&r==a[now].size){ 254 find_pool[++find_pool_tot]=now; 255 if(find_mmax<a[now].mmax) 256 find_cmax=max(find_mmax,a[now].cmax), 257 find_mmax=a[now].mmax; 258 else find_cmax=max(find_cmax,a[now].mmax); 259 return; 260 } 261 if(l<=a[a[now].lc].size) 262 sgt_find(a[now].lc,l,min(a[a[now].lc].size,r)); 263 if(r>a[a[now].lc].size) 264 sgt_find(a[now].rc,max(1,l-a[a[now].lc].size),r-a[a[now].lc].size); 265 } 266 int find(int l,int r,int now){ 267 find_pool_tot=0; 268 find_mmax=0,find_cmax=0; 269 sgt_find(now,l,r); 270 int trie_temper[21]; 271 for(int i=20;i>=1;i--) 272 trie_temper[i]=(find_cmax>>(i-1))&1; 273 for(int i=1;i<=find_pool_tot;i++) 274 fpnow[i]=a[find_pool[i]].rt,ansnow[i]=0; 275 for(int i=20;i>=1;i--){ 276 for(int j=1;j<=find_pool_tot;j++){ 277 if(!(trie_temper[i]&1)){ 278 if(tr[fpnow[j]].rc) 279 fpnow[j]=tr[fpnow[j]].rc,ansnow[j]+=(1<<(i-1)); 280 else fpnow[j]=tr[fpnow[j]].lc; 281 }else{ 282 if(tr[fpnow[j]].lc) 283 fpnow[j]=tr[fpnow[j]].lc,ansnow[j]+=(1<<(i-1)); 284 else fpnow[j]=tr[fpnow[j]].rc; 285 } 286 } 287 } 288 int tmpmax=0; 289 for(int i=1;i<=find_pool_tot;i++) 290 tmpmax=max(tmpmax,ansnow[i]); 291 return tmpmax; 292 } 293 int main(){ 294 freopen("ALOEXT.in","r",stdin); 295 freopen("ALOEXT.out","w",stdout); 296 scanf("%d%d",&n,&m); 297 for(int i=1;i<=n;i++) 298 scanf("%d",&rbd[i].val), 299 rbd[i].rt=trie_make(trie_newnode(),rbd[i].val); 300 rbd[n+1].rt=trie_make(trie_newnode(),0); 301 // for(int i=1;i<=1000000;i++)a[i].init(); 302 sgt_root=sgt_newnode(); 303 a[sgt_root].size=sgt_rebuild(sgt_root,1,n+1); 304 for(int i=1;i<=m;i++){ 305 scanf("%s",ch); 306 // if(tmmp[246]==2615874){// 307 // mmp[sgt_tot+1]=1;// 308 // }// 309 if(ch[0]=='I') 310 scanf("%d%d",&p,&x), 311 // sgt_breakdown(sgt_insert(sgt_root,x,p+1)), 312 sgt_breakdown(sgt_insert(sgt_root,(x+lsta)%MOD,(p+lsta)%n+1)), 313 n++; 314 else if(ch[0]=='D') 315 scanf("%d",&x), 316 // sgt_delete(x+1,sgt_root), 317 sgt_delete((x+lsta)%n+1,sgt_root), 318 n--; 319 else if(ch[0]=='C') 320 scanf("%d%d",&p,&x), 321 sgt_change((p+lsta)%n+1,sgt_root,(x+lsta)%MOD); 322 // sgt_change(p+1,sgt_root,x); 323 else if(ch[0]=='F')scanf("%d%d",&l,&r), 324 printf("%d\n",(lsta=find((l+lsta)%n+1,(r+lsta)%n+1,sgt_root))); 325 // printf("%d\n",(lsta=find(l+1,r+1,sgt_root))); 326 } 327 }