BZOJ3217ALOEXT 分块

Posted $mathit{AlphaINF}$

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了BZOJ3217ALOEXT 分块相关的知识,希望对你有一定的参考价值。

题目传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=3217

分块过掉辣!!!!!!$O(n^{1.5}+q\times \sqrt{n})$的分块过掉辣!!

而且速度贼快内存贼小啊(成功踩到b站第一)

由于此题需要强制在线的删除或者插入,所以我们基于块状链表分块,在每个块内存储指定区间内的所有数,以及该区间内的最大值和次大值,同时再维护一个由该区间内所有数组成的trie树。

对于修改一个数,首先在该块的trie数中删除该数(直接伪删),然后再插入,接着更新最大值和次大值。

对于插入一个数,直接在trie树中插入该数,随后在块状链表中插入,更新最大值和次大值。最后判断是否要将该块拆分(如果要察费直接暴力重构两个块即可)

对于删除一个数,trie树伪删除+块链删除+更新最大值和次大值。随后判断该块大小是否等于0(为零可以直接删掉这个块了)

对于查询最大值,首先查询出该区间内的次大值。对于完全包含的块,直接将该值丢到该块的trie树中求最大值,对于非完全包含的块,直接暴力求即可。

PS:经过测试,每个块的大小设置为3200最好(达到3200后切成两块1600的)。最初块大小为400,b站上跑了15.5s,把块大小改为3200后变成3.8s,直接rank1了。

  1 #include<bits/stdc++.h>
  2 #define M 5000000
  3 #define N 100
  4 using namespace std;
  5 struct trie{
  6     int a[2],sum;
  7 }p[M]; int uset=0;
  8 int add(int now,int x,int px){
  9     if(!now) now=++uset; 
 10     int ret=now;
 11     for(int i=19;i>=0;i--){
 12         bool k=x&(1<<i); p[now].sum+=px;
 13         if(p[now].a[k]) now=p[now].a[k];
 14         else uset++,p[now].a[k]=uset,now=uset;
 15     }
 16     p[now].sum+=px; 
 17     return ret;
 18 }
 19 int getmax(int now,int x){
 20     int ans=0; 
 21     for(int i=19;i>=0;i--){
 22         bool k=x&(1<<i); 
 23         if(p[p[now].a[1-k]].sum) 
 24         now=p[now].a[1-k],ans+=(1<<i);
 25         else now=p[now].a[k];
 26     }
 27     return ans;
 28 }
 29 struct kuai{
 30     int rt,use,next;
 31     int max1,max2,a[N*4+1];
 32     kuai(){
 33         rt=use=next=max1=max2=0;
 34         memset(a,0,sizeof(a));
 35     }
 36     void getmax(){
 37         max1=max2=0;
 38         for(int i=1;i<=use;i++)
 39         if(a[i]>max1) max2=max1,max1=a[i];
 40         else if(a[i]>max2) max2=a[i];
 41     }
 42 }a[N*7]; int use=1;
 43 void updata(int id,int zhi){
 44     for(int i=1;i;i=a[i].next) 
 45     if(a[i].use>=id){
 46         int last=a[i].a[id]; a[i].a[id]=zhi;
 47         a[i].rt=add(a[i].rt,last,-1);
 48         add(a[i].rt,zhi,1);
 49         a[i].getmax();
 50         return;
 51     }else id-=a[i].use;
 52 }
 53 void cut(int i){
 54     int j=++use;
 55     a[i].use=a[j].use=N*2;
 56     a[j].next=a[i].next; a[i].next=j;
 57     for(int k=1;k<=N*2;k++) 
 58     a[j].a[k]=a[i].a[k+N*2],a[i].a[k+N*2]=0;
 59     a[i].max1=a[i].max2=0;
 60     a[i].getmax(); a[j].getmax();
 61     a[i].rt=add(0,a[i].a[1],1);
 62     a[j].rt=add(0,a[j].a[1],1);
 63     for(int k=2;k<=N*2;k++){
 64         add(a[i].rt,a[i].a[k],1);
 65         add(a[j].rt,a[j].a[k],1);
 66     }
 67 }
 68 void insert(int x,int id){
 69     int i,pre; 
 70     for(i=1;i;pre=i,i=a[i].next) 
 71     if(a[i].use<id) id-=a[i].use;
 72     else break;
 73     if(!i) i=pre,id+=a[i].use;
 74     for(int j=a[i].use;j>=id;j--) a[i].a[j+1]=a[i].a[j];
 75     a[i].a[id]=x; a[i].use++;
 76     a[i].rt=add(a[i].rt,x,1);
 77     if(x>a[i].max1) a[i].max2=a[i].max1,a[i].max1=x;
 78     else if(x>a[i].max2) a[i].max2=x;
 79     if(a[i].use>=N*4) cut(i);
 80 }
 81 void del(int id){
 82     int i,pre=1,x;
 83     for(i=1;i;pre=i,i=a[i].next) 
 84     if(a[i].use<id) id-=a[i].use;
 85     else break;
 86     x=a[i].a[id]; add(a[i].rt,x,-1);
 87     for(int j=id;j<=a[i].use;j++) a[i].a[j]=a[i].a[j+1];
 88     a[i].use--; 
 89     if(a[i].use==0) {a[pre].next=a[i].next; return;}
 90     if(a[i].max2>x) return;
 91     a[i].getmax();
 92 }
 93 int getmax2(int l,int r){
 94     int max1=0,max2=0,sum=0;
 95     int i,pre;
 96     for(i=1;i;pre=i,i=a[i].next){
 97         if(l<=sum+1&&sum+a[i].use<=r){
 98             if(a[i].max1>max1) max2=max1,max1=a[i].max1;
 99             else if(a[i].max1>max2) max2=a[i].max1;
100             if(a[i].max2>max2) max2=a[i].max2; 
101         }
102         else if(sum+1<=l&&r<=sum+a[i].use){
103             for(int j=l-sum;j<=r-sum;j++)
104             if(a[i].a[j]>max1) max2=max1,max1=a[i].a[j];
105             else if(a[i].a[j]>max2) max2=a[i].a[j];
106         }
107         else if(sum+1<=l&&l<=sum+a[i].use){
108             for(int j=l-sum;j<=a[i].use;j++)
109             if(a[i].a[j]>max1) max2=max1,max1=a[i].a[j];
110             else if(a[i].a[j]>max2) max2=a[i].a[j];
111         }
112         else if(sum+1<=r&&r<=sum+a[i].use){
113             for(int j=1;j<=r-sum;j++)
114             if(a[i].a[j]>max1) max2=max1,max1=a[i].a[j];
115             else if(a[i].a[j]>max2) max2=a[i].a[j];
116         }
117         sum+=a[i].use;
118     }
119     return max2;
120 }
121 int query(int l,int r){
122     int x=getmax2(l,r),maxn=0,sum=0;
123     int i,pre;
124     for(i=1;i;pre=i,i=a[i].next){
125         if(l<=sum+1&&sum+a[i].use<=r){
126             maxn=max(maxn,getmax(a[i].rt,x));
127         }
128         else if(sum+1<=l&&r<=sum+a[i].use){
129             for(int j=l-sum;j<=r-sum;j++)
130             maxn=max(maxn,x^a[i].a[j]);
131         }
132         else if(sum+1<=l&&l<=sum+a[i].use){
133             for(int j=l-sum;j<=a[i].use;j++)
134             maxn=max(maxn,x^a[i].a[j]);
135         }
136         else if(sum+1<=r&&r<=sum+a[i].use){
137             for(int j=1;j<=r-sum;j++)
138             maxn=max(maxn,x^a[i].a[j]);
139         }
140         sum+=a[i].use;
141     }
142     return maxn;
143 }
144 int main(){
145     int n,m,lastans=0,n0;
146     scanf("%d%d",&n,&m); n0=n;
147     for(int i=1;i<=n;i++){
148         int x; scanf("%d",&x);
149         insert(x,i);
150     }
151     while(m--){
152         char c[10]; int x,y;
153         scanf("%s%d",c,&x);
154         x=(x+lastans)%n0+1;
155         if(c[0]==D){del(x); n0--;continue;}
156         scanf("%d",&y);
157         if(c[0]==F) y=(y+lastans)%n0+1;
158         else y=(y+lastans)%1048576;
159         if(c[0]==I) insert(y,x),n0++;
160         if(c[0]==C) updata(x,y);
161         if(c[0]==F) printf("%d\n",lastans=query(min(x,y),max(x,y)));
162     }
163 }

 

以上是关于BZOJ3217ALOEXT 分块的主要内容,如果未能解决你的问题,请参考以下文章

BZOJ 3217: ALOEXT

BZOJ3217ALOEXT 替罪羊树+Trie树

bzoj3217ALOEXT 替罪羊树套Trie树

瞎题表

bzoj2002 弹飞绵羊 分块

BZOJ.3920.Yuuna的礼物(莫队 分块套分块)