题目
又是一道分块踩爆
log
2
\log^2
log2的经典题目。
因为有插入,用块状链表就行了。
对于每个块维护一个Trie树维护01串,一个SET维护次大值(其实是我懒得自己用分块写)。
Trie树这个东西其实对分块很不友好的,他修改查询都是
log
\log
log,无法通过平衡分块复杂度来得到更好的结果。
修改直接插入块内的Trie
O
(
log
n
)
O(\log n)
O(logn),
询问暴力询问边角块
O
(
n
)
O(\sqrt n)
O(n),中间的跑Trie
O
(
n
log
n
)
O(\sqrt n\log n)
O(nlogn)。
复杂度还可进一步改进。
设块的大小为
S
S
S
发现复杂度为
O
(
log
n
)
+
O
(
S
)
+
O
(
n
S
log
n
)
O(\log n) + O(S) + O(\frac nS \log n)
O(logn)+O(S)+O(Snlogn)
显然修改复杂度太低况且如前文所说我们也没什么平衡它与询问复杂度的方法。
所以只需要考虑后面两项。
S
=
n
log
n
S = \sqrt{n\log n}
S=nlogn是取最值:
复杂度
O
(
n
n
log
n
)
O(n\sqrt {n\log n})
O(nnlogn)
比
log
2
\log^2
log2快多了。
借鉴了一下dalao的博客。
目前2928msB站Rank1(让dalao获得了Rank2的好成绩真是对不起呢)
AC Code:
#include<bits/stdc++.h>
#define maxn 200005
#define maxpt maxn * 60
#define S 655
using namespace std;
char cb[1<<15],*cs=cb,*ct=cb;
#define getc() (cs==ct&&(ct=(cs=cb)+fread(cb,1,1<<15,stdin),cs==ct)?0:*cs++)
inline void read(int &res){
char ch;
for(;!isdigit(ch=getc()););
for(res=ch-'0';isdigit(ch=getc());res=res*10+ch-'0');
}
int n,m,n0;
int id[maxn];
int ch[maxpt][2],siz[maxpt],tot;
void Insert_trie(int &now,int x,int v){
if(!now) now = ++tot;
for(int i=19,u=now;i>=0;i--){
int &p = ch[u][(x>>i&1)];
if(!p) p = ++tot;
u = p;
siz[u]+=v;
}
}
struct block{
int lb,rb;
int a[S*2+10],rt,siz;
multiset<int>st;
}B[maxn/S+1];
int fbl=1,cnt_bl=0;
multiset<int>::reverse_iterator it;
void Delete(int x){
int bl = fbl;
for(;B[bl].rb && B[bl].siz < x;x-=B[bl].siz,bl=B[bl].rb);
B[bl].st.erase(B[bl].st.find(B[bl].a[x-1]));
Insert_trie(B[bl].rt,B[bl].a[x-1],-1);
for(int i=x-1;i<B[bl].siz-1;i++) B[bl].a[i] = B[bl].a[i+1];
B[bl].siz--;
if(!B[bl].siz){
if(!B[bl].lb) fbl = B[bl].rb , B[fbl].lb = 0;
else B[B[bl].lb].rb = B[bl].rb , B[B[bl].rb].lb = B[bl].lb;
}
}
int seq[maxn],pre[maxn],suc[maxn],cnt=0;
int Query(int x,int y){
int Bst=0,sst=0,lb=fbl,rb=fbl;
for(;B[lb].rb && B[lb].siz<x;x-=B[lb].siz,lb=B[lb].rb);
for(;B[rb].rb && B[rb].siz<y;y-=B[rb].siz,rb=B[rb].rb);
//printf("%d %d %d %d\n",lb,rb,x,y);
if(lb == rb){
for(int i=x-1;i<y;i++)
{
if(B[lb].a[i] > Bst) sst = Bst , Bst = B[lb].a[i];
else sst = max(sst , B[lb].a[i]);
//printf("%d ",B[lb].a[i]);
}
//puts("");
//printf("%d\n ",sst);
int ret = 0;
for(int i=x-1;i<y;i++){
ret = max(ret , sst ^ B[lb].a[i]);
//printf("%d ",sst ^ B[lb].a[i]);
}
//puts("");
return ret;
}
else{
for(int i=x-1;i<B[lb].siz;i++)
if(B[lb].a[i] > Bst) sst = Bst , Bst = B[lb].a[i];
else sst = max(sst , B[lb].a[i]);
for(int i=0;i<y;i++)
if(B[rb].a[i] > Bst) sst = Bst , Bst = B[rb].a[i];
else sst = max(sst , B[rb].a[i]);
cnt = 0;
for(int i=B[lb].rb;i!=rb;i=B[i].rb){
it = B[i].st.rbegin();
if(it!=B[i].st.rend()){
if((*it) > Bst) sst = Bst , Bst = (*it);
else sst = max(sst , (*it));
it++;
if(it!=B[i].st.rend()){
if((*it) > Bst) sst = Bst , Bst = (*it);
else sst = max(sst , (*it));
}
}
seq[++cnt] = B[i].rt;
pre[cnt] = cnt-1 , suc[cnt-1] = cnt;
}
suc[cnt] = cnt+1;
int ret = 0;
if(cnt)
{
ret = sst;
for(int i=19;i>=0;i--){
bool flag = 0 , p = ((sst>>i&1)^1);
//printf("%d\n",);
for(int j=suc[0];j!=cnt+1;j=suc[j])
{
//printf("%d\n",siz[ch[seq[j]][p]]);
if(siz[ch[seq[j]][p]]) flag = 1;
}
if(flag){
for(int j=suc[0];j!=cnt+1;j=suc[j]){
seq[j] = ch[seq[j]][p];
if(!seq[j])
pre[suc[j]] = pre[j],
suc[pre[j]] = suc[j];
}
ret ^= (1<<i) * p;
}
else{
for(int j=suc[0];j!=cnt+1;j=suc[j]){
seq[j] = ch[seq[j]][!p];
if(!seq[j])
pre[suc[j]] = pre[j],
suc[pre[j]] = suc[j];
}
ret ^= (1<<i) * (!p);
}
}
}
for(int i=x-1;i<B[lb].siz;i++)
ret = max(ret , B[lb].a[i]^sst);
for(int i=0;i<y;i++)
ret = max(ret , B[rb].a[i]^sst);
return ret;
}
}
void split(int x){
B[++cnt_bl].lb=x,B[cnt_bl].rb=B[x].rb;
B[B[x].rb].lb=cnt_bl,B[x].rb=cnt_bl;
B[x].siz-=S,B[cnt_bl].siz=S;
memcpy(B[cnt_bl].a,B[x].a+B[x].siz,S*sizeof(int));
for(int i=0;i<S;i++)
Insert_trie(B[cnt_bl].rt,B[cnt_bl].a[i],1),
Insert_trie(B[x].rt,B[cnt_bl].a[i],-1),
B[cnt_bl].st.insert(B[cnt_bl].a[i]),
B[x].st.erase(B[x].st.find(B[cnt_bl].a[i]));
}
void Insert(int x,int y){
int lb = fbl;
for(;B[lb].rb && B[lb].siz < x;x-=B[lb].siz,lb=B[lb].rb);
for(int i=B[lb].siz;i>x;i--) B[lb].a[i] = B[lb].a[i-1];
B[lb].siz++;
B[lb].a[x]=y;
B[lb].st.insert(y);
Insert_trie(B[lb].rt,y,1);
if(B[lb].siz >= 2 * S)
split(lb);
}
void Modify(int x,int y){
int lb = fbl;
for(;B[lb].rb && B[lb].siz < x;x-=B[lb].siz,lb=B[lb].rb);
//printf("%d\n",x);
int py = B[lb].a[x-1];B[lb].a[x-1] = y;
//for(multiset<int>::iterator it=B[lb].st.begin();it!=B[lb].st.end();it++)
// printf("%d ",*it);
//puts("");
//printf("%d\n",B[lb].st.count(py));
B[lb].st.erase(B[lb].st.find(py));
B[lb].st.insert(y);
Insert_trie(B[lb].rt,py,-1);
Insert_trie(B[lb].rt,y,1);
}
int main(){
//int t1=clock();
//freopen("1.in","r",stdin);
//freopen("1.out","w",stdout);
read(n),read(m);n0 = n;
for(int i=0,x;i<n;i++){
read(x);
B[i/S+1].a[B[i/S+1].siz] = x;
Insert_trie(B[i/S+1].rt,x,1),
B[i/S+1].st.insert(x);
B[i/S+1].siz ++;
}
cnt_bl = (n-1)/S+1;
for(int i=2;i<=cnt_bl;i++)
B[i-1].rb = i ,
B[i].lb = i-1 ;
char s[2];
for(int x,y,la=0;m--;){
for(;!isalpha(s[0]=getc()););
//puts("1");
//puts(s);
if(s[0] == 'D'){
read(x);
x=(x+la) % n0;
//for(int i=0;i<B[fbl].siz;i++)
// printf("%d ",B[fbl].a[i]);puts("");
//printf("%d\n",x+1);
Delete(x+1);
n0--;
}
else{
read(x),read(y);
if(s[0] == 'F'){
x=(x+la) % n0 , y=(y+la) % n0;
//for(int i=0;i<B[2].siz;i++)
printf("%d ",B[2].a[i]);puts("");
//for(int j=fbl;j;j=B[j].rb)
//for(int i=0;i<B[j].siz;i++)
// printf("%d ",B[j].a[i]);
//puts("");
//printf("%d %d\n",x+1,y+1);
printf("%d\n",la=Query(x+1,y+1));
}
else {
x=(x+la) % n0 , y=(y+la) % 1048576;
//printf("%d\n",fbl);
// for(int i=0;i<B[j].siz;i++)
// printf("%d ",B[j].a[i]);puts("");
//printf("%d %d\n",x+1,y);
if(s[0] == 'I') n0 ++ , Insert(x,y);
else Modify(x+1,y);
}
}
}
//freopen("CON","w",stdout);
//printf("%d\n",clock()-t1);
}