版权声明:本文为博主原创文章,未经博主允许必须转载。 https://blog.csdn.net/C20181220_xiang_m_y/article/details/88720274
题目分析:
由于这位dalao实在讲的太好了,所以我就直接引用了。。
由于此题需要强制在线的删除或者插入,所以我们基于块状链表分块,在每个块内存储指定区间内的所有数,以及该区间内的最大值和次大值,同时再维护一个由该区间内所有数组成的trie树。
对于修改一个数,首先在该块的trie数中删除该数(直接伪删(减cnt)),然后再插入,接着更新最大值和次大值。
对于插入一个数,直接在trie树中插入该数,随后在块状链表中插入,更新最大值和次大值。最后判断是否要将该块拆分(如果要察费直接暴力重构两个块即可)
对于删除一个数,trie树伪删除+块链删除+更新最大值和次大值。随后判断该块大小是否等于0(为零可以直接删掉这个块了)
对于查询最大值,首先查询出该区间内的次大值。对于完全包含的块,直接将该值丢到该块的trie树中求最大值,对于非完全包含的块,直接暴力求即可。
再分析一波时间复杂度,记块大小为
:
插入:找位置
,暴力移动
,修改trie树
,维护次大值
,分裂块
删除:找位置
,暴力移动
,修改trie树
,维护次大值
修改:找位置
,修改trie树
,维护次大值
询问:查找次大值
,查找答案
所以总的复杂度比
略小,m是操作次数,S开个
差不多,所以我就开了1200。(然而测了测开1400比较快,到2019-03-21 16:46:17 似乎是b站rank3?疯狂%块状链表。。 )
Code:
#include<cstdio>
#include<cctype>
#include<vector>
#include<algorithm>
#define LL long long
#define S 1400
#define M 5000000
using namespace std;
inline void read(int &a){
char c;bool f=0;
while(!isdigit(c=getchar())) if(c=='-') f=1;
for(a=c-'0';isdigit(c=getchar());a=a*10+c-'0');
if(f) a=-a;
}
int ch[M][2],cnt[M],sz;
void add(int &now,int x,int d){
if(!now) now=++sz;
int r=now;bool v;
for(int i=19;i>=0;i--,r=ch[r][v]){
if(!ch[r][v=x>>i&1]) ch[r][v]=++sz;
cnt[ch[r][v]]+=d;
}
}
int askmax(int r,int x){
int ret=0;bool v;
for(int i=19;i>=0;i--,r=ch[r][v]){
if(cnt[ch[r][v=!(x>>i&1)]]) ret+=1<<i;
else v=!v;
}
return ret;
}
struct Block{
int siz,nxt,rt,mx1,mx2,b[S*2+1];
void updmax(){
mx1=mx2=0;
for(int i=1;i<=siz;i++)
if(b[i]>mx1) mx2=mx1,mx1=b[i];
else if(b[i]>mx2) mx2=b[i];
}
}a[185];
int n,m,block=1,ans;
void cut(int i){
int j=++block;
a[i].siz=a[j].siz=S;
a[j].nxt=a[i].nxt,a[i].nxt=j;
for(int k=1;k<=S;k++) a[j].b[k]=a[i].b[k+S],a[i].b[k+S]=0;
a[i].updmax(),a[j].updmax();
a[i].rt=a[j].rt=0;
for(int k=1;k<=S;k++) add(a[i].rt,a[i].b[k],1),add(a[j].rt,a[j].b[k],1);
}
void insert(int id,int x){
int i,pre;
for(i=1;i;pre=i,i=a[i].nxt)
if(a[i].siz<id) id-=a[i].siz;
else break;
if(!i) i=pre,id+=a[i].siz;
for(int j=a[i].siz;j>=id;j--) a[i].b[j+1]=a[i].b[j];
a[i].b[id]=x,a[i].siz++;
add(a[i].rt,x,1);
if(x>a[i].mx1) a[i].mx2=a[i].mx1,a[i].mx1=x;
else if(x>a[i].mx2) a[i].mx2=x;
if(a[i].siz>=S*2) cut(i);
}
void del(int id){
int i,x,pre=1;
for(i=1;;pre=i,i=a[i].nxt)
if(a[i].siz<id) id-=a[i].siz;
else break;
add(a[i].rt,x=a[i].b[id],-1);
for(int j=id;j<=a[i].siz;j++) a[i].b[j]=a[i].b[j+1];
if(!(--a[i].siz)) {a[pre].nxt=a[i].nxt;return;}
if(x>=a[i].mx2) a[i].updmax();
}
void modify(int id,int x){
int i,last;
for(i=1;;i=a[i].nxt)
if(a[i].siz<id) id-=a[i].siz;
else break;
add(a[i].rt,last=a[i].b[id],-1),add(a[i].rt,a[i].b[id]=x,1);
if(max(last,x)>=a[i].mx2) a[i].updmax();
}
int getmax2(int l,int r){
int x=0,y=0;
for(int i=1;r>=1;i=a[i].nxt){
if(l<=1&&a[i].siz<=r){
if(a[i].mx1>x) y=max(x,a[i].mx2),x=a[i].mx1;
else y=max(y,a[i].mx1);
}
else{
for(int j=max(1,l),ed=min(r,a[i].siz);j<=ed;j++)
if(a[i].b[j]>x) y=x,x=a[i].b[j];
else if(a[i].b[j]>y) y=a[i].b[j];
}
l-=a[i].siz,r-=a[i].siz;
}
return y;
}
int query(int l,int r){
int x=getmax2(l,r),ret=0;
for(int i=1;r>=1;i=a[i].nxt){
if(l<=1&&a[i].siz<=r) ret=max(ret,askmax(a[i].rt,x));
else for(int j=max(1,l),ed=min(r,a[i].siz);j<=ed;j++) ret=max(ret,a[i].b[j]^x);
l-=a[i].siz,r-=a[i].siz;
}
return ret;
}
int main()
{
//freopen("H.in","r",stdin);
char op;int x,y;
const int mod = (1<<20)-1;
read(n),read(m);
for(int i=1;i<=n;i++) read(x),insert(i,x);
while(m--){
while(!isalpha(op=getchar()));
read(x),x=(x+ans)%n+1;
if(op=='D') {del(x),n--;continue;}
read(y),op=='F'?(y=(y+ans)%n+1):(y=(y+ans)&mod);
if(op=='I') insert(x,y),n++;
if(op=='C') modify(x,y);
if(op=='F') printf("%d\n",ans=query(x,y));
}
}