BZOJ4517[Scoi2016]美味——主席树

题目描述

一家餐厅有 n 道菜,编号 1...n ,大家对第 i 道菜的评价值为 ai(1≤i≤n)。有 m 位顾客,第 i 位顾客的期
望值为 bi,而他的偏好值为 xi 。因此,第 i 位顾客认为第 j 道菜的美味度为 bi XOR (aj+xi),XOR 表示异或
运算。第 i 位顾客希望从这些菜中挑出他认为最美味的菜,即美味值最大的菜,但由于价格等因素,他只能从第 
li 道到第 ri 道中选择。请你帮助他们找出最美味的菜。
 

输入

第1行,两个整数,n,m,表示菜品数和顾客数。
第2行,n个整数,a1,a2,...,an,表示每道菜的评价值。
第3至m+2行,每行4个整数,b,x,l,r,表示该位顾客的期望值,偏好值,和可以选择菜品区间。
1≤n≤2×10^5,0≤ai,bi,xi<10^5,1≤li≤ri≤n(1≤i≤m);1≤m≤10^5
 

输出

 输出 m 行,每行 1 个整数,ymax ,表示该位顾客选择的最美味的菜的美味值。

样例输入

4 4
1 2 3 4
1 4 1 4
2 3 2 3
3 2 3 3
4 1 2 4

样例输出

9
7
6
7
 
  一看到位异或第一时间就会想到按位从高到底贪心,这道题也是这样的,但稍有不同的是要两个数的和与另一个数位异或结果最大。还是从高位到低位考虑,如果b当前为是1(0的方法一样),那么希望x+a这一位是0,因为更高位已经确定了,所以满足要求的a+x的值一定是一个区间——假设更高位已经确定的答案是ans(ans的值即为更高位贪心取最优解,其他位都是0),那么a+x的区间就是[ans,ans+(1<<i)-1],把x挪到等号那边就能知道要使这一位异或结果最优所需的a的范围,只要在主席树上查询是否有这个区间内的数,有的话把ans的这一位加上b这一位相反的数。因为得到的ans是a+x的值,所以最后还要ans^=b。
#include<set>
#include<map>
#include<queue>
#include<stack>
#include<cmath>
#include<cstdio>
#include<vector>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
int n,m;
int l,r;
int cnt;
int ans;
int maxv;
int a,b,x;
int ls[4000010];
int rs[4000010];
int sum[4000010];
int root[200010];
int updata(int pre,int l,int r,int v)
{
    int rt=++cnt;
    if(l==r)
    {
        sum[rt]=sum[pre]+1;
        return rt;
    }
    ls[rt]=ls[pre];
    rs[rt]=rs[pre];
    sum[rt]=sum[pre]+1;
    int mid=(l+r)>>1;
    if(v<=mid)
    {
        ls[rt]=updata(ls[pre],l,mid,v);
    }
    else
    {
        rs[rt]=updata(rs[pre],mid+1,r,v);
    }
    return rt;
}
int query(int x,int y,int l,int r,int L,int R)
{
    if(L<=l&&r<=R)
    {
        return sum[y]-sum[x];
    }
    int mid=(l+r)>>1;
    if(L>mid)
    {
        return query(rs[x],rs[y],mid+1,r,L,R);
    }
    else if(R<=mid)
    {
        return query(ls[x],ls[y],l,mid,L,R);
    }
    else
    {
        return query(ls[x],ls[y],l,mid,L,R)+query(rs[x],rs[y],mid+1,r,L,R);
    }
}
bool find(int l,int r,int L,int R)
{
    L=max(0,L);
    R=min(maxv,R);
    if(L>R)
    {
        return 0;
    }
    else
    {
        return query(root[l],root[r],0,1<<18,L,R);
    }
}
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&a);
        maxv=max(a,maxv);
        root[i]=updata(root[i-1],0,1<<18,a);
    }
    for(int j=1;j<=m;j++)
    {
        scanf("%d%d%d%d",&b,&x,&l,&r);
        ans=0;
        for(int i=17;i>=0;i--)
        {
            int now=ans+((((b>>i)&1)^1)<<i);
            if(find(l-1,r,now-x,now+(1<<i)-1-x))
            {
                ans=now;
            }
            else
            {
                ans+=(((b>>i)&1)<<i);
            }
        }
        printf("%d
",ans^b);
    }
}
原文地址:https://www.cnblogs.com/Khada-Jhin/p/9449376.html