• P3293-[SCOI2016]美味【主席树】


    正题

    题目链接:https://www.luogu.com.cn/problem/P3293


    题目大意

    给出一个长度为(n)的序列,(m)次询问给出(b,x,l,r)表示询问在([l,r])中找到一个数字(a)使得(b xor (a+x))的值最大。

    (1leq n,mleq 2 imes10^5,0leq a,b,x<10^5)


    解题思路

    (Trie)上想就很容易卡思路,考虑正常情况下我们是怎么求(b xor a)最大的。

    其实在(Trie)树上条等价于每次询问一个区间内有没有值然后再选择往左或者往右,现在这个(x)就是相当于把我们询问的区间移动了,既然(Trie)树解决不了这样的问题那么就考虑一下主席树。

    定义一下(z)表示异或的那个数的基数(前面枚举的位已经确定),从大到小枚举(i),若(b)的第(i)位有那么最好是让(a+x)的第(i)位没有,也就是询问([z-x,z-x+2^i))。如果第(i)位没有那么最好是(a+x)的第(i)位有,那么询问([z-x+2^i,z-x+2^{i+1}))就好了。

    时间复杂度(O(nlog^2 n))


    code

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    const int N=2e5+10,M=N<<5,Li=1e5;
    int n,m,cnt,rt[N],w[M],ls[M],rs[M];
    int Change(int x,int L,int R,int pos){
    	int now=++cnt;w[now]=w[x]+1;
    	if(L==R)return now;
    	int mid=(L+R)>>1;
    	if(pos<=mid)ls[now]=Change(ls[x],L,mid,pos),rs[now]=rs[x];
    	else rs[now]=Change(rs[x],mid+1,R,pos),ls[now]=ls[x];
    	return now;
    }
    int Ask(int x,int y,int L,int R,int l,int r){
    	if(!(w[y]-w[x]))return 0;
    	if(L==l&&R==r)return w[y]-w[x];
    	int mid=(L+R)>>1;
    	if(r<=mid)return Ask(ls[x],ls[y],L,mid,l,r);
    	if(l>mid)return Ask(rs[x],rs[y],mid+1,R,l,r);
    	return Ask(ls[x],ls[y],L,mid,l,mid)+Ask(rs[x],rs[y],mid+1,R,mid+1,r);
    }
    int Query(int L,int R,int l,int r){
    	if(l<0)l=0;if(r>Li)r=Li;if(r<l)return 0;
    	return Ask(rt[L-1],rt[R],0,Li,l,r);
    }
    int main()
    {
    	scanf("%d%d",&n,&m);
    	for(int i=1;i<=n;i++){
    		int x;scanf("%d",&x);
    		rt[i]=Change(rt[i-1],0,Li,x);
    	}
    	while(m--){
    		int b,a,l,r,z=0,ans=0;
    		scanf("%d%d%d%d",&b,&a,&l,&r);
    		for(int i=17;i>=0;i--){
    			if((b>>i)&1){
    				if(Query(l,r,z-a,z-a+(1<<i)-1))
    					ans|=(1<<i);
    				else z|=(1<<i);
    			}
    			else{
    				if(Query(l,r,z-a+(1<<i),z-a+(1<<i+1)-1))
    					ans|=(1<<i),z|=(1<<i);
    			}
    		}
    		printf("%d
    ",ans);
    	}
    	return 0;
    }
    
  • 相关阅读:
    OCI读取单条记录(C)
    共享内存shmget shmat shmdt
    Linux系统下的多线程编程入门
    如何让errno多线程/进程安
    linux的mount(挂载)命令详解
    取得系统时间并以BCD形式保存到字符串中
    电脑上的搜索功能用不了了,怎么办?
    如何建立Linux下的ARM交叉编译环境
    C#网络编程之Http请求
    深入了解Oracle前滚恢复rolling forward(一)
  • 原文地址:https://www.cnblogs.com/QuantAsk/p/14877636.html
Copyright © 2020-2023  润新知