洛谷P3293 [SCOI2016]美味(主席树)

传送门

 

据说这题做法叫做可持久化trie树?(然而我并不会)

首先考虑一下贪心,从高位到低位枚举,如果能选1肯定比选0优

假设已经处理到了$b$的第$i$位,为1(为0的话同理就不说了)

那么只有当$a_j+x$的第$i$位为0时才能让答案的第$i$位为$1$

考虑把$x$的影响去掉。如果当前的答案是$ans$(即令前面几位贪心情况下最大且第$i$位为0时的$a$),那么只有在区间$[ans-x,ans+(1<<i)-1-x]$的数能在加上$x$之后第$i$位为0(这个可以自己手动算一算)

如果存在,那么$ans$第$i$位变为0(存在前$i$位与之相同且第$i$位为0的$a_i$),否则变为1(只存在前$i$位与之相同且第$i$位为0的$a_i$)

然后查找是两个区间限制主席树套上去就好了

 1 //minamoto
 2 #include<iostream>
 3 #include<cstdio>
 4 using namespace std;
 5 #define getc() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
 6 char buf[1<<21],*p1=buf,*p2=buf;
 7 template<class T>inline bool cmax(T&a,const T&b){return a<b?a=b,1:0;}
 8 template<class T>inline bool cmin(T&a,const T&b){return a>b?a=b,1:0;}
 9 inline int read(){
10     #define num ch-'0'
11     char ch;bool flag=0;int res;
12     while(!isdigit(ch=getc()))
13     (ch=='-')&&(flag=true);
14     for(res=num;isdigit(ch=getc());res=res*10+num);
15     (flag)&&(res=-res);
16     #undef num
17     return res;
18 }
19 char sr[1<<21],z[20];int C=-1,Z;
20 inline void Ot(){fwrite(sr,1,C+1,stdout),C=-1;}
21 inline void print(int x){
22     if(C>1<<20)Ot();if(x<0)sr[++C]=45,x=-x;
23     while(z[++Z]=x%10+48,x/=10);
24     while(sr[++C]=z[Z],--Z);sr[++C]='\n';
25 }
26 const int N=2e5+5,M=N*20;
27 int rt[N],L[M],R[M],sum[M],a[N],cnt,n,q,m;
28 void update(int &now,int last,int x,int l=0,int r=m){
29     sum[now=++cnt]=sum[last]+1;
30     if(l==r) return;
31     int mid=(l+r)>>1;
32     if(x<=mid) R[now]=R[last],update(L[now],L[last],x,l,mid);
33     else L[now]=L[last],update(R[now],R[last],x,mid+1,r);
34 }
35 int query(int u,int v,int ql,int qr,int l=0,int r=m){
36     if(ql<=l&&qr>=r) return sum[u]-sum[v];
37     int mid=(l+r)>>1;
38     if(ql<=mid&&query(L[u],L[v],ql,qr,l,mid)) return 1;
39     if(qr>mid&&query(R[u],R[v],ql,qr,mid+1,r)) return 1;
40     return 0;
41 }
42 inline int find(int u,int v,int ql,int qr){
43     cmax(ql,0),cmin(qr,m);
44     if(ql>qr) return 0;
45     return query(rt[u],rt[v],ql,qr);
46 }
47 int main(){
48 //    freopen("testdata.in","r",stdin);
49     n=read(),q=read();
50     for(int i=1;i<=n;++i) cmax(m,a[i]=read());
51     for(int i=1;i<=n;++i)
52     update(rt[i],rt[i-1],a[i]);
53     while(q--){
54         int b=read(),x=read(),ql=read(),qr=read(),ans=0;
55         for(int i=17;i>=0;--i){
56             int now=ans+((1^((b>>i)&1))<<i);
57             if(find(ql-1,qr,now-x,now+(1<<i)-1-x)) ans=now;
58             else ans+=((b>>i)&1)<<i;
59         }
60         print(ans^b);
61     }
62     Ot();
63     return 0;
64 }

 

posted @ 2018-09-26 17:54  bztMinamoto  阅读(186)  评论(0编辑  收藏  举报
Live2D