SCOI2016 美味

题目链接:戳我

如果没有偏移的话,就是模板了,但是加上了偏移,肯定不能直接上01trie了。

看到异或,我们想到要按位处理。

因为只有a和原先的区间中间的数有关,因为是区间,所以先把它放到主席树里面。然后之后查询的话,每输入一个b和x,我们可以按位贪心的和b异或。

具体是什么意思呢,就是如果当前b的第i位为1的话,我们就要看看这个区间里面有没有存在的。

然后答案累加上该位的贡献,然后继续在这个基础上进行上面的贪心操作即可。

但是有个问题

代码如下:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#define MAXN 200010
using namespace std;
int n,m,tot,ans;
int a[MAXN+10],rt[MAXN+10];
struct Node{int ls,rs,sum;}t[MAXN*32];
inline void update(int &x,int f,int l,int r,int k)
{
    x=++tot;
    t[x]=t[f];t[x].sum++;
    if(l==r) return;
    int mid=(l+r)>>1;
    if(k<=mid) update(t[x].ls,t[f].ls,l,mid,k);
    else update(t[x].rs,t[f].rs,mid+1,r,k);
}
inline int query(int x,int f,int l,int r,int ll,int rr)
{
    int cur=t[x].sum-t[f].sum,cur_ans=0;
    if(ll<=l&&r<=rr) return cur;
    int mid=(l+r)>>1;
    if(ll<=mid) cur_ans+=query(t[x].ls,t[f].ls,l,mid,ll,rr);
    if(mid<rr) cur_ans+=query(t[x].rs,t[f].rs,mid+1,r,ll,rr);
    return cur_ans;
}
int main()
{
    #ifndef ONLINE_JUDGE
    freopen("ce.in","r",stdin);
    #endif
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&a[i]);
        update(rt[i],rt[i-1],1,MAXN,a[i]);
    }
    // for(int i=1;i<=n;i++) printf("a[%d]=%d
",i,a[i]); puts("");
    // for(int i=1;i<=n;i++) printf("rt[%d]=%d
",i,rt[i]);
    for(int i=1;i<=m;i++)
    {
        int b,x,l,r,k,ll,rr,ans=0;
        scanf("%d%d%d%d",&b,&x,&l,&r);
        for(int j=17;j>=0;j--)
        {
            if(b&(1<<j))
            {
                ll=ans,rr=ans+(1<<j)-1;
                k=0;
            }
            else 
            {
                ll=ans+(1<<j),rr=ans+(1<<(j+1))-1;
                k=1;
            }
            if(!query(rt[r],rt[l-1],1,MAXN,max(1,ll-x),min(MAXN,rr-x))) k^=1;
            ans|=(k<<j);
        }
        printf("%d
",ans^b);
    }
    return 0;
}
原文地址:https://www.cnblogs.com/fengxunling/p/10806043.html