題目傳送門: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了。
UPD:前段時間被卡到第二,后來重新把塊大小調整為2620,並且加上fread與fwrite,卡到3312ms,重回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 }