十二省联考2019 异或粽子

十二省联考2019 异或粽子


傻逼题,全场切的那种。

显然每次取出没取过的异或和最大的区间。

对于每个r,将满足[l,r]异或和最大的区间插入进堆里。

每次取出堆顶区间,如果取出过k个以r为右端点的区间了,就向堆中插入满足[l,r]异或和第k+1大的区间。

傻逼可持久化trie,就做完了。

#include<bits/stdc++.h>
#define il inline
#define vd void
il unsigned int gi(){
    unsigned int x=0,f=1;
    char ch=getchar();
    while(!isdigit(ch)){
        if(ch=='-')f=-1;
        ch=getchar();
    }
    while(isdigit(ch))x=x*10+ch-'0',ch=getchar();
    return x*f;
}
unsigned int a[500010];
std::priority_queue<std::pair<unsigned int,int> >que;
int rt[500010],ch[17000010][2],sum[17000010],cnt;
int qk[500010];
il int copyof(int x){
    ++cnt;ch[cnt][0]=ch[x][0],ch[cnt][1]=ch[x][1],sum[cnt]=sum[x];
    return cnt;
}
il vd insert(int&rt,unsigned int y){
    rt=copyof(rt);++sum[rt];
    int x=rt;
    for(int i=31;~i;--i){
        bool t=(y>>i)&1;
        ch[x][t]=copyof(ch[x][t]);
        x=ch[x][t];++sum[x];
    }
}
il unsigned int query(int x,int k,unsigned int y){
    unsigned int ret=0;
    for(int i=31;~i;--i){
        bool t=!((y>>i)&1);
        if(k<=sum[ch[x][t]])x=ch[x][t],ret|=(1u<<i);
        else k-=sum[ch[x][t]],x=ch[x][!t];
    }
    return ret;
}
int main(){
#ifdef XZZSB
    freopen("in.in","r",stdin);
    freopen("out.out","w",stdout);
#endif
    int n=gi(),K=gi();
    for(int i=1;i<=n;++i)a[i]=a[i-1]^gi();
    for(int i=0;i<=n;++i){
        if(i)rt[i]=rt[i-1];
        insert(rt[i],a[i]);
    }
    for(int i=1;i<=n;++i)que.push({query(rt[i],qk[i]=1,a[i]),i});
    long long ans=0;
    while(K--){
        int r=que.top().second;
        ans+=que.top().first;
        que.pop();
        if(qk[r]!=r)que.push({query(rt[r],++qk[r],a[r]),r});
    }
    printf("%lld\n",ans);
    return 0;
}
posted @ 2019-04-11 22:27  菜狗xzz  阅读(198)  评论(0编辑  收藏  举报