链接:点击打开链接
题意:
给定一个非负整数序列 {a},初始长度为n。
有 m 个操作,有以下两种操作类型:
A x:添加操作,表示在序列末尾添加一个数 x,序列的长度 n+1。
Q l r x:询问操作,你需要找到一个位置 p,满足,使得: 最大,输出最大是多少。
代码:
#include
using namespace std;
const int siz=70*300005;
int num_tr,node;
int rk[siz],a[siz],tr[siz][2];
void in(int x){
int i,op,rt;
rt=rk[num_tr];
rk[++num_tr]=++node;
for(i=24;i>=0;i--){
op=(x>>i)&1;
a[node]=a[rt]+1;
tr[node][op]=node+1;
tr[node][!op]=tr[rt][!op];
rt=tr[rt][op];
++node;
}
a[node]=a[rt]+1;
}
int cal(int l,int r,int x){
int i,op,ans=0;
for(i=24;i>=0;i--){
op=(x>>i)&1;
if(a[tr[r][!op]]-a[tr[l][!op]]>0){
ans=(ans<<1)|1;
l=tr[l][!op];
r=tr[r][!op];
}
else{
ans<<=1;
l=tr[l][op];
r=tr[r][op];
}
}
return ans;
}
int main(){ //可持久化字典树,跟主席树其实是一个意思
char c; //原问题转换一下其实就是n个数中找一个与
int n,m,i,j,u,v,w,sum; //已知的数异或的最大值,直接在trie树上贪心
scanf("%d%d",&n,&m);
sum=num_tr=node=0;
in(0);
for(i=1;i<=n;i++){
scanf("%d",&u);
sum^=u;
in(sum);
}
while(m--){
getchar();
scanf("%c",&c);
if(c=='A'){
scanf("%d",&u);
sum^=u;
in(sum);
}
else{
scanf("%d%d%d",&u,&v,&w); //最后询问要注意一下是哪两颗树
printf("%d\n",cal(rk[u-1],rk[v],sum^w));
}
}
return 0;
}