洛谷P3293 【[SCOI2016]美味】

题意

传送门

分析

(Akamey's) (blog)

题意是查询一段区间中的异或和的最大值,所以可以想到按位贪心

也就是说,我们枚举当前可能的答案(ans=a[i]+x)的每一位(从高到低),于是我们可以发现,

最终答案(a[i])一定落在:

(large [ans+(1<<i)-x,ans+(1<<(i+1))-1-x]) (quad large (b[i])这一位为(large 0))

(large [ans-x,ans+(1<<i)-1-x]) (quad large (b[i])这一位为(large1))

上面两种情况分别对应(b[i])的当前位为(0)(1)的情况

(b[i])(0),则当前位为(1)答案更优

(b[i])(1),则当前位为(0)答案更优

所以我们直接查询在两段值域区间内有没有数即可,如果有,那么继续下一位的枚举,当前这一位就变成(1/0),如果没有,那么当前这一位就变成(0/1),还是继续下一位,直到结束

此时(ans=a[i]+x),所以我们直接(ans igoplus b)就是最优的答案

因为要区间查询值域上数的个数,所以我们用值域线段树来维护

但是我们这样干只能记录对于下标区间([1,n])的值域线段树(也就是全局),但是我们这里还要求某一个特定区间([l,r])当中的值域线段树

这就是主席树的经典应用了,静态区间第(k)大的问题中我们就用过值域线段树维护值域,然后用下标的差来维护区间即可

所以我们这里采用主席树来维护值域就行了

代码

#include<bits/stdc++.h>
using namespace std;
template <typename T>
inline void read(T &x){
	x=0;char ch=getchar();bool f=false;
	while(!isdigit(ch)){if(ch=='-'){f=true;}ch=getchar();}
	while(isdigit(ch)){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
	x=f?-x:x;
	return ;
}
template <typename T,typename... Args> inline void read(T& t, Args&... args){read(t);read(args...);}
template <typename T>
inline void write(T x){
	if(x<0) putchar('-'),x=-x;
	if(x>9) write(x/10);
	putchar(x%10^48);
	return ;
}
template <typename T>
inline void print(T x){write(x),putchar(' ');}
#define ll long long
#define ull unsigned long long
#define inc(x,y) (x+y>=MOD?x+y-MOD:x+y)
#define dec(x,y) (x-y<0?x-y+MOD:x-y)
#define min(x,y) (x<y?x:y)
#define max(x,y) (x>y?x:y)
const int N=2e5+5,M=1e5+5,MOD=1e9+7;
int n,m,a[N],b[N],root[N],cnt;
struct Segment_Tree{
	int sum,ls,rs;
	#define sum(x) Tree[x].sum
	#define ls(x) Tree[x].ls
	#define rs(x) Tree[x].rs
}Tree[N<<5];
void build(int &rt,int l,int r){
	rt=++cnt;
	if(l==r){sum(rt)=0;return;}
	int mid=l+r>>1;
	build(ls(rt),l,mid),build(rs(rt),mid+1,r);
	return ;
}
void modify(int &rt,int pre,int l,int r,int pos,int v){
	rt=++cnt;
	if(l==r){sum(rt)=sum(pre)+v;return ;}
	int mid=l+r>>1;
	ls(rt)=ls(pre),rs(rt)=rs(pre),sum(rt)=sum(pre)+v;
	if(pos<=mid) modify(ls(rt),ls(pre),l,mid,pos,v);
	else modify(rs(rt),rs(pre),mid+1,r,pos,v);
	return ;
}
bool query(int u,int v,int l,int r,int ql,int qr){
	if(sum(v)-sum(u)<1) return false;
	if(ql<=l&&r<=qr) return true;
	int mid=l+r>>1,res=0;
	if(ql<=mid) res+=query(ls(u),ls(v),l,mid,ql,qr);
	if(qr>mid) res+=query(rs(u),rs(v),mid+1,r,ql,qr);
	return res;
}

int main(){
	read(n),read(m);build(root[0],0,M);
	for(int i=1;i<=n;i++){
		read(a[i]);
		modify(root[i],root[i-1],0,M,a[i],1);
	}
	for(int i=1,b,x,l,r;i<=m;i++){
		read(b),read(x),read(l),read(r);
		int ans=0;
		for(int k=17;k>=0;k--){
			int L,R,op;
			if(b&(1<<k)) L=ans,R=ans+((1<<k)-1),op=0;
			else L=ans+(1<<k),R=ans+((1<<(k+1))-1),op=1;
			if(!query(root[l-1],root[r],0,M,max(L-x,0),min(R-x,M))) op^=1;
			ans+=(op<<k);
		}
		write(ans^b),putchar('
');
	}
	system("Pause");
	return 0;
}
原文地址:https://www.cnblogs.com/Akmaey/p/14310192.html