【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 imes 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,MAXM);
14     for(int i=1;i<=n;i++)
15         printf("%d ",rand()%MAXS);
16     printf("
");
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
",rand()%n,rand()%MAXS);
22             n++;
23         }else if(rnd_tsk==1){
24             printf("D %d
",rand()%n);
25             n--;
26         }else if(rnd_tsk==2){
27             int l=rand()%(n-1);
28             printf("F %d %d
",l,l+rand()%(n-l-1)+1);
29         }else if(rnd_tsk==3){
30             printf("C %d %d
",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
",(lsta=find((l+lsta)%n+1,(r+lsta)%n+1,sgt_root)));
325 //            printf("%d
",(lsta=find(l+1,r+1,sgt_root)));
326     }
327 }
原文地址:https://www.cnblogs.com/skylynf/p/7376297.html