bzoj [Scoi2016]美味

 [Scoi2016]美味

Time Limit: 30 Sec  Memory Limit: 256 MB
Submit: 721  Solved: 391
[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

HINT

 

Source

 

题解:

区间最大异或值的经典做法是可持久化trie,但是加上一个数的话可持久化trie就变得非常的扯淡

考虑可持久化trie其实可以等价为一颗上限为2^k-1的主席树,在trie上确定一位其实相当于将答案的区间缩小的一半,也就是在主席树上向下走一层

当所有数加上x之后,我们在主席树上走的时候就不能直接调用siz[son[x][0]],但是因为所有数都被加了,所以我们其实要查询的是左子树的区间向前窜x位之后的区间有没有数,这样的话每次走的时候在主席树上重新查[l-x,mid-x]或者[mid+1-x,r-x]来判断应该往哪边走即可,复杂度多了个log,但是n=2*10^5,不虚

然后就过了

时间复杂度O(m log^2 n)

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <iostream>
 4 using namespace std;
 5 const int N=1<<18;
 6 const int maxn=200010;
 7 int n,m,tot;
 8 int rt[maxn];
 9 struct node
10 {
11     int ls,rs,siz;
12 }s[maxn*30];
13 void insert(int x,int &y,int l,int r,int a)
14 {
15     y=++tot,s[y].siz=s[x].siz+1;
16     if(l==r)    return ;
17     int mid=(l+r)>>1;
18     if(a<=mid)   s[y].rs=s[x].rs,insert(s[x].ls,s[y].ls,l,mid,a);
19     else    s[y].ls=s[x].ls,insert(s[x].rs,s[y].rs,mid+1,r,a);
20 }
21 int query(int l,int r,int x,int y,int a,int b)
22 {
23     if(a<=l&&r<=b)    return s[x].siz-s[y].siz;
24     int mid=(l+r)>>1;
25     if(b<=mid)   return query(l,mid,s[x].ls,s[y].ls,a,b);
26     if(a>mid)    return query(mid+1,r,s[x].rs,s[y].rs,a,b);
27     return query(l,mid,s[x].ls,s[y].ls,a,b)+query(mid+1,r,s[x].rs,s[y].rs,a,b);
28 }
29 inline int find(int l,int r,int a,int b)
30 {
31     int i,j=0,d;
32     for(i=1<<18;i;i>>=1)
33     {
34         d=(b&i)>0;
35         if(d&&!query(0,N,rt[r],rt[l-1],j-a,j+i-a-1))    j+=i;
36         if(!d&&query(0,N,rt[r],rt[l-1],j+i-a,j+i+i-a-1))    j+=i;
37     }
38     return b^j;
39 }
40 inline int rd()
41 {
42     int ret=0,f=1;  char gc=getchar();
43     while(gc<'0'||gc>'9') {if(gc=='-')    f=-f;   gc=getchar();}
44     while(gc>='0'&&gc<='9')   ret=ret*10+gc-'0',gc=getchar();
45     return ret*f;
46 }
47 int main()
48 {
49     int i,a,b,c,d;
50     n=rd(),m=rd();
51     for(i=1;i<=n;i++)  
52         a=rd(),insert(rt[i-1],rt[i],0,N,a);
53     for(i=1;i<=m;i++)
54     {
55         a=rd(),b=rd(),c=rd(),d=rd();
56         printf("%d\n",find(c,d,b,a));
57     }
58 }

 

posted @ 2017-12-29 09:22  Kaiser-  阅读(176)  评论(0编辑  收藏  举报