一、题目
二、解法
外层就是一个线段树,所有节点上保存一个 t i r e tire tire树,我们完全可以把所有 t i r e tire tire树压在一起,写一个可持久化 t i r e tire tire树,把这个可持久化理解成前缀和, l o w e r _ b o u n d lower\_bound lower_bound找出一个答案产生的后缀,差分之后询问就行了。
#include <cstdio>
#include <vector>
#include <iostream>
using namespace std;
const int M = 100005;
int read()
{
int x=0,flag=1;char c;
while((c=getchar())<'0' || c>'9') if(c=='-') flag=-1;
while(c>='0' && c<='9') x=(x<<3)+(x<<1)+(c^48),c=getchar();
return x*flag;
}
int n,m,cnt,rt[M];
struct node
{
int x,y;//版本时间,根的编号
bool operator < (const node &b) const
{
if(x==b.x) return y<b.y;
return x<b.x;
}
}tp;vector<node> t[4*M];
struct tree
{
int num,ch[2];//tire树上的点
}tr[420*M];
int get(int x)//新建树上节点
{
int t=++cnt;
tr[t]=tr[x];tr[t].num++;
return t;
}
int add(int x,int y)//根x中插入一个y值
{
int ret=get(x),p=ret;
for(int i=16;i>=0;i--)
{
int f=y>>i&1;
tr[p].ch[f]=get(tr[x].ch[f]);
x=tr[x].ch[f];p=tr[p].ch[f];
}
return ret;
}
int ask(int x,int y,int v)//根(x,y]中v产生的异或最大值
{
if(tr[x].num==tr[y].num) return 0;
int ret=0;
for(int i=16;i>=0;i--)
{
int f=v>>i&1;
if(tr[tr[x].ch[!f]].num<tr[tr[y].ch[!f]].num)
{
x=tr[x].ch[!f];
y=tr[y].ch[!f];
ret+=(1<<i);
}
else
{
x=tr[x].ch[f];
y=tr[y].ch[f];
}
}
return ret;
}
void build(int i,int l,int r)//建树,防止越界
{
t[i].push_back(node{0,0});
if(l==r) return ;
int mid=(l+r)>>1;
build(i<<1,l,mid);
build(i<<1|1,mid+1,r);
}
void Add(int i,int l,int r,int p,int v)//单点修改
{
tp.y=add(t[i][t[i].size()-1].y,v);
t[i].push_back(tp);//保存版本
if(l==r) return ;
int mid=(l+r)>>1;
if(mid>=p) Add(i<<1,l,mid,p,v);
else Add(i<<1|1,mid+1,r,p,v);
}
int Ask(int i,int l,int r,int L,int R,int d,int v)//区间查询
{
if(L>r || l>R) return 0;
if(L<=l && r<=R)
{
if(t[i][t[i].size()-1].x<d) return 0;
vector<node>::iterator x=lower_bound(t[i].begin(),t[i].end(),node{d,0});
if(x!=t[i].begin()) x--;//需要减一,开区间
return ask(x->y,t[i][t[i].size()-1].y,v);
}
int mid=(l+r)>>1;
return max(Ask(i<<1,l,mid,L,R,d,v),Ask(i<<1|1,mid+1,r,L,R,d,v));
}
int main()
{
n=read();m=read();
for(int i=1;i<=n;i++)
rt[i]=add(rt[i-1],read());//特殊物品
build(1,1,n);
for(int i=1,t=0;i<=m;i++)
{
int op=read(),l=read(),r=read();
if(op==0)
{
tp.x=++t;
Add(1,1,n,l,r);
}
else
{
int x=read(),d=read();
d=max(0,t-d+1);//闭区间
printf("%d\n",max(Ask(1,1,n,l,r,d,x),ask(rt[l-1],rt[r],x)));
}
}
}