[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 }