bzoj 4571: [Scoi2016]美味 (主席树)

链接:https://www.lydsy.com/JudgeOnline/problem.php?id=4571

题面;

4571: [Scoi2016]美味

Time Limit: 30 Sec  Memory Limit: 256 MB
Submit: 1089  Solved: 633
[Submit][Status][Discuss]

Description

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

Input

第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
 

Output

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

Sample Input

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

Sample Output

9
7
6
7
 
 
思路:
对b逐位分析,根据当前位找到能使其当前位异或为1的数的范围,在主席树中查找这个范围内是否存在数字。
如  b第4位为1.那么要使第四位异或为1,范围就是  xxx0000 到 xxx0999
 
实现代码;
#include<bits/stdc++.h>
using namespace std;
const int M = 2e5+10;
int ls[M*40],rs[M*40],sum[M*40],idx,rt[M];
void update(int old,int &k,int p,int c,int l,int r){
    k = ++idx;
    ls[k] = ls[old]; rs[k] = rs[old];
    sum[k] = sum[old] + c;
    if(l == r) return ;
    int mid = (l + r) >> 1;
    if(p <= mid) update(ls[old],ls[k],p,c,l,mid);
    else update(rs[old],rs[k],p,c,mid+1,r);
}

int query(int old,int k,int L,int R,int l,int r){
    if(L <= l&&R >= r){
        return sum[k] - sum[old];
    }
    int mid = (l + r) >> 1;
    int ret = 0;
    if(L <= mid) ret += query(ls[old],ls[k],L,R,l,mid);
    if(R > mid) ret += query(rs[old],rs[k],L,R,mid+1,r);
    return ret;
}

int main()
{
    int n,m,b,l,r,x;
    scanf("%d%d",&n,&m);
    for(int i = 1;i <= n;i ++) cin>>x,update(rt[i-1],rt[i],x,1,0,M);
    for(int i = 1;i <= m;i ++){
        scanf("%d%d%d%d",&b,&x,&l,&r);
        int a = 0;
        for(int j = 17;j >= 0;j --){
            if(b&(1<<j)){
                int mn = max(0,a-x),mx = (a|(1<<j)-1)-x;
                if(mx < 0||!query(rt[l-1],rt[r],mn,mx,0,M)) a ^= (1<<j);
            }
            else{
                a^=(1<<j);
                int mn = max(0,a-x),mx = (a|(1<<j)-1)-x;
                if(mx < 0||!query(rt[l-1],rt[r],mn,mx,0,M)) a^= (1<<j);
            }
        }
        printf("%d\n",a^b);
    }
}

 

posted @ 2019-04-23 13:08  冥想选手  阅读(208)  评论(0编辑  收藏  举报