1. 程式人生 > >bzoj 4571 [Scoi2016]美味——主席樹

bzoj 4571 [Scoi2016]美味——主席樹

col lse getch bzoj con namespace ace 需要 ret

題目:https://www.lydsy.com/JudgeOnline/problem.php?id=4571

按位考慮,需要的就是一個區間;比如最高位就是(2^k -x)。

對於不是最高位的位置該怎麽考慮?其實之前位置如果能或不能匹配上,也就相當於指定了之前的位上的是0還是1;把是1的位累計進一個變量裏,加到區間的邊界上就行了!

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=2e5+5
,M=1e5+5,K=N*20; int n,m,mx,a[N],rt[N],tot,sm[K],ls[K],rs[K]; int ans,lj,lo,hi,bin[20]; int rdn() { int ret=0;bool fx=1;char ch=getchar(); while(ch>9||ch<0){if(ch==-)fx=0;ch=getchar();} while(ch>=0&&ch<=9) ret=(ret<<3)+(ret<<1)+ch-0,ch=getchar();
return fx?ret:-ret; } void build(int &cr,int pre,int l,int r,int v) { cr=++tot; ls[cr]=ls[pre]; rs[cr]=rs[pre]; sm[cr]=sm[pre]+1; if(l==r) return; int mid=l+r>>1; if(v<=mid) build(ls[cr],ls[pre],l,mid,v); else build(rs[cr],rs[pre],mid+1,r,v); } bool query(int cr,int pre,int
l,int r,int L,int R) { if(l>=L&&r<=R) return sm[cr]-sm[pre]; int mid=l+r>>1; bool fg=0; if(L<=mid) fg=query(ls[cr],ls[pre],l,mid,L,R); if(!fg&&mid<R) fg=query(rs[cr],rs[pre],mid+1,r,L,R); return fg; } void init() { bin[0]=1; for(int i=1;i<=18;i++) bin[i]=bin[i-1]<<1; } int main() { n=rdn(); m=rdn(); init(); for(int i=1;i<=n;i++) a[i]=rdn(),mx=max(mx,a[i]); for(int i=1;i<=n;i++) build(rt[i],rt[i-1],1,mx,a[i]); for(int i=1,b,x,l,r;i<=m;i++) { b=rdn(); x=rdn(); l=rdn(); r=rdn(); ans=0; lj=0; for(int j=17;j>=0;j--) { if(b&bin[j]) {lo=lj; hi=lj+bin[j]-1;} else {lo=lj+bin[j]; hi=lj+bin[j+1]-1;} hi-=x; lo-=x; hi=min(hi,mx); lo=max(lo,0); if(lo<=hi&&query(rt[r],rt[l-1],1,mx,lo,hi)) lj+=(b&bin[j]?0:bin[j]),ans+=bin[j]; else lj+=(b&bin[j]?bin[j]:0); } printf("%d\n",ans); } return 0; }

bzoj 4571 [Scoi2016]美味——主席樹