[BZOJ4571][SCOI2016]美味(贪心+主席树)

经典问题,按位贪心,每次需要知道的是”在这一位之前的位都以确定的情况下,能否找到这一位是0/1的数”,这就是在询问[L,R]内某个值域区间是否有数,主席树即可。

 1 #include<cstdio>
 2 #include<algorithm>
 3 #define rep(i,l,r) for (int i=(l); i<=(r); i++)
 4 using namespace std;
 5 
 6 const int N=200010,M=300000;
 7 int n,m,b,x,l,r,nd,rt[N],a[N],ls[N*20],rs[N*20],v[N*20];
 8 
 9 void ins(int &x,int y,int L,int R,int pos){
10     x=++nd; v[x]=v[y]+1; ls[x]=ls[y]; rs[x]=rs[y];
11     if (L==R) return;
12     int mid=(L+R)>>1;
13     if (pos<=mid) ins(ls[x],ls[y],L,mid,pos);
14         else ins(rs[x],rs[y],mid+1,R,pos);
15 }
16 
17 int que(int x,int y,int L,int R,int l,int r){
18     if (L==l && r==R) return v[y]-v[x];
19     int mid=(L+R)>>1;
20     if (r<=mid) return que(ls[x],ls[y],L,mid,l,r);
21     else if (l>mid) return que(rs[x],rs[y],mid+1,R,l,r);
22         else return que(ls[x],ls[y],L,mid,l,mid)+que(rs[x],rs[y],mid+1,R,mid+1,r);
23 }
24 
25 int main(){
26     freopen("bzoj4571.in","r",stdin);
27     freopen("bzoj4571.out","w",stdout);
28     scanf("%d%d",&n,&m);
29     rep(i,1,n) scanf("%d",&a[i]),ins(rt[i],rt[i-1],0,M,a[i]);
30     rep(i,1,m){
31         scanf("%d%d%d%d",&b,&x,&l,&r); int a=0;
32         for (int j=17; ~j; j--){
33             if (!(b&(1<<j))) a|=1<<j;
34             int L=max(a-x,0),R=(a|((1<<j)-1))-x;
35             if (R<0 || !que(rt[l-1],rt[r],0,M,L,R)) a^=1<<j;
36         }
37         printf("%d\n",a^b);
38     }
39     return 0;
40 }

 

posted @ 2018-12-09 10:41  HocRiser  阅读(101)  评论(0编辑  收藏  举报