1. 程式人生 > >[BZOJ4571][SCOI2016]美味(貪心+主席樹)

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