P3293 [SCOI2016]美味 主席树+按位贪心

给定长度为 \(n\) 序列 \(a[i]\) ,每次询问区间 \([l,r]\) ,并给定 \(b,x\) 中的一个数 \(p=a[i]\) ,使得最大化 \(b \bigoplus p^x\)

主席树+按位贪心。
我们可以直接贪每一位长什么样子,然后再主席树上区间查询即可。

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#define R register int
using namespace std;
namespace Luitaryi {
inline int g() { R x=0,f=1;
    register char s; while(!isdigit(s=getchar())) f=s=='-'?-1:f;
    do x=x*10+(s^48); while(isdigit(s=getchar())); return x*f;
} const int N=200010,B=17;
int n,m,L,tot,a[N];
int sum[N*20],ls[N*20],rs[N*20],rt[N];
inline void ins(int& tr,int t,int l,int r,int p) {
    tr=++tot; sum[tr]=sum[t]+1,ls[tr]=ls[t],rs[tr]=rs[t];
    if(l==r) return ; R md=l+r>>1;
    p<=md?ins(ls[tr],ls[t],l,md,p):ins(rs[tr],rs[t],md+1,r,p);
}
inline bool query(int tr,int t,int l,int r,int LL,int RR) {
    if(r<LL||l>RR||sum[tr]-sum[t]<=0) return 0;
    if(l==r) return sum[tr]-sum[t];
    R md=l+r>>1;
    return (LL<=md&&ls[tr]&&query(ls[tr],ls[t],l,md,LL,RR))
                ||(RR>md&&rs[tr]&&query(rs[tr],rs[t],md+1,r,LL,RR));
}
inline void main() {
    n=g(),m=g();
    for(R i=1;i<=n;++i) a[i]=g(),L=max(L,a[i]);
    for(R i=1;i<=n;++i) ins(rt[i],rt[i-1],0,L,a[i]);
    for(R i=1,b,x,l,r,ans;i<=m;++i) { ans=0;
        b=g(),x=g(),l=g(),r=g();
        for(R t=B;~t;--t) {
            if((b>>t&1)&&!query(rt[r],rt[l-1],0,L,ans-x,ans+(1<<t)-1-x)) ans+=1<<t;
            if(!(b>>t&1)&&query(rt[r],rt[l-1],0,L,ans+(1<<t)-x,ans+(1<<t+1)-1-x)) ans+=1<<t;
        } printf("%d\n",b^ans);
    }
}
} signed main() {Luitaryi::main(); return 0;}

2019.11.23

猜你喜欢

转载自www.cnblogs.com/Jackpei/p/11919861.html