bzoj 4571: [Scoi2016]美味 (主席树)
链接:https://www.lydsy.com/JudgeOnline/problem.php?id=4571
题面;
4571: [Scoi2016]美味
Time Limit: 30 Sec Memory Limit: 256 MBSubmit: 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
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
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); } }