您的位置:首页 > 其它

BZOJ 4571: [Scoi2016]美味(权值线段树查询最大异或和)

2018-03-26 15:34 453 查看

题目大意

给定一个序列a1~an

给定若干个询问, b , x , L , R

最大化b xor (ai+x)|L<=i<=R

分析

不考虑x这个偏移量我们用二进制trie

现在考虑了有一个新操作就是权值线段树

把ai全部丢到权值线段树里面

假设我们所有的数二进制长度不超过5

假设我们贪心地选择了待选择的ai的前两位是10(之前选择的时候我们可以保证有这样的a存在)

考虑当前如何贪心,b的第三位是1,根据贪心我们希望a的第三位是0,那么我们就查询是否存在a的值属于[10000,10011](前两位不变,第三位为0),存在我们就把a的第三位选择为0即可,否则只有选择1。

其中b的第三位为0的时候操作差不多。

区间查询的时候加上变量就好了

注意

二进制是从0开始的,但这并不意味着你应该在高位-1

比如这里的极限是2^17

那么你就该从第17位一直考虑到0,不要妄图从16开始考虑

还有就是17位全部为1的话要用(1<<18)-1

坑了我好久啊啊啊啊啊啊啊啊啊啊啊啊

还有就是要判断空区间的情况,以及最好保证查询的区间被包含于(l,r),虽然好像只要有交集就可以弄对,但是容易出细节问题哎。

代码

#include<bits/stdc++.h>
using namespace std;
const int maxn=2e5+105,oo=17,N=(1<<oo)-1;
struct SegmentTree{
int np,rt[maxn],lc[maxn*22],rc[maxn*22],sz[maxn*22];
void Initial()
{
np=0;
memset(rt,0,sizeof(rt));
memset(lc,0,sizeof(lc));
memset(rc,0,sizeof(rc));
}
void pushup(int now)
{
sz[now]=sz[lc[now]]+sz[rc[now]];
}
void Build(int &now,int L,int R)
{
now=++np;
if(L==R)
{
sz[now]=0;
return;
}
int m=(L+R)>>1;
Build(lc[now],L,m);
Build(rc[now],m+1,R);
pushup(now);
}
int Newnode(int now)
{
++np;
lc[np]=lc[now];rc[np]=rc[now];sz[np]=sz[now];
return np;
}
void modify(int pre,int &now,int L,int R,int i)
{
now=Newnode(pre);
if(L==R)
{
sz[now]++;
return;
}
int m=(L+R)>>1;
if(i<=m) modify(lc[pre],lc[now],L,m,i);
else modify(rc[pre],rc[now],m+1,R,i);
pushup(now);
}
int query(int now1,int now2,int L,int R,int i,int j)//[i,j]的范围大一点没有关系,只要和[l,R]有交集即可
{
if(i<=L && R<=j)
return sz[now2]-sz[now1];
int m=(L+R)>>1,ret=0;
if(i<=m)ret+=query(lc[now1],lc[now2],L,m,i,j);
if(j>m) ret+=query(rc[now1],rc[now2],m+1,R,i,j);
return ret;
}
}sgt;
int n,m;
void Init()
{
int a;
sgt.Initial();
sgt.Build(sgt.rt[0],0,N);
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
{
scanf("%d",&a);
sgt.modify(sgt.rt[i-1],sgt.rt[i],0,N,a);
}
}
int Q,x,l,r;
int DFS(int a,int b,int i)//这里是返回a+x的最优值
{
if(a==b)return a;
int mid=(a+b)>>1;
if( Q & (1<<i) )//第i位为1,那么我们希望a为0
{
if(max(0,a-x)<=min(N,mid-x) && sgt.query(sgt.rt[l-1],sgt.rt[r],0,N,max(0,a-x),min(N,mid-x) ) )
return DFS(a,mid,i-1);
else
return DFS(mid+1,b,i-1);
}
else
{
if(max(0,mid+1-x)<=min(N,b-x) && sgt.query(sgt.rt[l-1],sgt.rt[r],0,N,max(0,mid+1-x),min(N,b-x) ) )
return DFS(mid+1,b,i-1);
else
return DFS(a,mid,i-1);
}
}
int main()
{
//freopen("in.txt","r",stdin);
//freopen("out1.txt","w",stdout);
Init();
while(m--)
{
scanf("%d%d%d%d",&Q,&x,&l,&r);
printf("%d\n",Q^DFS(0, ( 1<<(oo+1) )-1 , oo ) );
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: