题目链接:点击打开链接
题目大意:有n个数a1~an m次查询 每次查询给出 val l r ,l r 询问val异或al~ar之间最大的值是多少。
解题思路:
怎么说呢,算是一道很典型的主席树模板题吧,但是自己太水了,因为之前没怎么做过01字典树的题目,所以对01字典树的认识就只停留在一个模板,也不知道是怎么实现的。所以当时比赛没想到把主席树和01字典树结合起来,所以比赛的时候采用了01字典树加莫队的做法,不过当时一直wa,有个bug没调出来,后来发现是因为01字典树是不能进行先删后加的操作的,这也是用模板的坏处吧,什么都不知道,不过最后改了以后还是t了,当时傻了,因为字典树的每次更新都是O(30),莫队想实现的话其实最主要就是更新答案的操作需要是O(1) ,所以最后复杂度n*30*根号n 就炸了,最后只过了85的数据,不过令我很费解的是我写的纯暴力代码过了95的数据,我真是惊了。。。
接下来说正解,正解其实就是主席树加01字典树的结合,如果两个知识点都明白的话应该是很容易理解做法的,每次更新都判断在每一层应该让0处数值+1 还是1处数值+1 最后维护一个主席树,查询的时候利用主席树的性质直接进行区间之间的查询+01字典树的判断即可。
Ac代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=1e5+5;
const ll INF=1e18+7;
const int mod=998244353;
int n,m,cnt,x,root[maxn];
struct node //主席树结点
{
int l,r,sum;
}t[maxn*40];
void update(int &x,int y,int k,int dep)
{
t[++cnt]=t[y],t[cnt].sum++,x=cnt;
if(dep<0) return ;
if((k>>dep)&1) update(t[x].l,t[y].l,k,dep-1); //判断当前层是1还是0 更新相应的位置
else update(t[x].r,t[y].r,k,dep-1);
}
int query(int x,int y,int k,int dep) //查询
{
if(dep<0) return 0;
if((k>>dep)&1) //01字典树性质 如果当前为1 就拿0和它异或
{
if(t[t[y].r].sum-t[t[x].r].sum>0) return (1<<dep)+query(t[x].r,t[y].r,k,dep-1); //如果l r之间的数中有此位为0的数 则ans+1<<dep
else return query(t[x].l,t[y].l,k,dep-1);
}
else
{
if(t[t[y].l].sum-t[t[x].l].sum>0) return (1<<dep)+query(t[x].l,t[y].l,k,dep-1);
else return query(t[x].r,t[y].r,k,dep-1);
}
}
int main()
{
cnt=0;
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%d",&x),update(root[i],root[i-1],x,30);
scanf("%d",&m);
for(int i=1;i<=m;i++)
{
int val,l,r;
scanf("%d%d%d",&val,&l,&r);
printf("%d\n",query(root[l-1],root[r],val,30));
}
system("pause");
}