题意
给定一个初始时为空的整数序列(元素由1开始标号)以及一些询问:
类型1:在数组后面就加入数字x。
类型2:在区间L…R中找到y,最大化(x xor y)。
类型3:删除数组最后K个元素。
类型4:在区间L…R中,统计小于等于x的元素个数。
类型5:在区间L…R中,找到第k小的数。
n,x<=500000
分析
学吉司机的历史最值学到生无可恋,来刷道水题放松放松。
直接上可持久化trie即可。
代码
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=500005;
int n,bin[25],root[N],sz,m;
struct tree{int l,r,size;}t[N*21];
int read()
{
int x=0,f=1;char ch=getchar();
while (ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while (ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
void ins(int &d,int p,int x,int y)
{
d=++sz;t[d]=t[p];t[d].size++;
if (x==-1) return;
if (!(y&bin[x])) ins(t[d].l,t[p].l,x-1,y);
else ins(t[d].r,t[p].r,x-1,y);
}
int query1(int d,int p,int x,int y)
{
if (x==-1) return 0;
if (!(y&bin[x]))
{
if (t[t[d].r].size-t[t[p].r].size) return query1(t[d].r,t[p].r,x-1,y)+bin[x];
else return query1(t[d].l,t[p].l,x-1,y);
}
else
{
if (t[t[d].l].size-t[t[p].l].size) return query1(t[d].l,t[p].l,x-1,y);
else return query1(t[d].r,t[p].r,x-1,y)+bin[x];
}
}
int query2(int d,int p,int x,int y)
{
if (x==-1) return t[d].size-t[p].size;
if (!(y&bin[x])) return query2(t[d].l,t[p].l,x-1,y);
else return query2(t[d].r,t[p].r,x-1,y)+t[t[d].l].size-t[t[p].l].size;
}
int query3(int d,int p,int x,int y)
{
if (x==-1) return 0;
if (t[t[d].l].size-t[t[p].l].size>=y) return query3(t[d].l,t[p].l,x-1,y);
else return query3(t[d].r,t[p].r,x-1,y-t[t[d].l].size+t[t[p].l].size)+bin[x];
}
int main()
{
m=read();
bin[0]=1;
for (int i=1;i<=20;i++) bin[i]=bin[i-1]*2;
while (m--)
{
int op=read();
if (op==1)
{
int x=read();n++;
ins(root[n],root[n-1],19,x);
}
else if (op==2)
{
int l=read(),r=read(),x=read();
printf("%d\n",query1(root[r],root[l-1],19,x));
}
else if (op==3)
{
int x=read();
n-=x;
}
else if (op==4)
{
int l=read(),r=read(),x=read();
printf("%d\n",query2(root[r],root[l-1],19,x));
}
else
{
int l=read(),r=read(),x=read();
printf("%d\n",query3(root[r],root[l-1],19,x));
}
}
return 0;
}