zoukankan      html  css  js  c++  java
  • 洛谷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;
    }
  • 相关阅读:
    ZJOI2019 Day1 游记
    Codeforces Round #545 (Div. 1)
    AtCoder WTF 2019 C2. Triangular Lamps Hard
    析合树
    Codeforces Round #539 (Div. 1)
    Codeforces 1103 E. Radix sum
    Codeforces 1097 G. Vladislav and a Great Legend
    sts创建spring项目
    servlet项目demo
    IDEA中创建maven web项目
  • 原文地址:https://www.cnblogs.com/Akmaey/p/14310192.html
Copyright © 2011-2022 走看看