BZOJ5495 [2019省队联测]异或粽子

北城余情 提交于 2020-02-12 14:33:09

题意:

给定一个序列,问最大的k段连续异或和的代数和。

知识点:

可持久化Trie,堆

解法:

首先异或的一个性质可以把连续子串转化成前缀和的形式维护。

然后看到异或代数和最大,可以想到可持久化Trie。

但是维护的方法又有两种。

第一种也是我一开始想到的,把n个值最大的放到堆中,每次从堆中取出一个元素,更新答案;然后找出这个元素唯一对应的下一个值(暴力跳trie,最多不超过64次)。但是太难了。

第二种就是超级钢琴的做法,在l到r中找到最大的答案为pos点,然后放入l到pos-1和pos-1到r继续更新答案即可。

备注:

这种超级钢琴的做法很值得学习。注意这道题堆里面要维护的是l,r,pos,val,id,id不可以省。

代码:

#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;

typedef long long ll;
const int maxn=500010;
int n,m,tot,bit[35],rt[maxn];
ll ans,sum[maxn];
struct trie
{
    int ch[2],tag,id;
}a[maxn*40];
struct data
{
    int l,r;
    ll val;
    int pos,id;
    bool operator <(const data &b)const
    {
        return val<b.val;
    }
};
priority_queue<data>q;

ll read()
{
    ll x=0;
    char c=getchar();
    while (c<48||c>57)
        c=getchar();
    while (c>=48&&c<=57)
        x=(x<<1)+(x<<3)+(c^48),c=getchar();
    return x;
}

void div(ll x)
{
    int i;
    for (i=31;i>=0;i--)
    {
        bit[i]=(x&1);
        x>>=1;
    }
}

void insert(int &x,int y,int id)
{
    x=(++tot);
    a[x].tag=id;
    int i,u=x;
    for (i=0;i<=31;i++)
    {
        a[u].ch[bit[i]]=(++tot);
        a[tot].tag=id;
        if (y)
            a[u].ch[bit[i]^1]=a[y].ch[bit[i]^1];
        u=a[u].ch[bit[i]];
        if (y)
            y=a[y].ch[bit[i]];
    }
    a[u].id=id;
}

ll query(int l,int r,int &pos)
{
    pos=0;
    ll res=0;
    int i,u=rt[r];
    for (i=0;i<=31;i++)
    {
        if (a[u].ch[bit[i]^1]&&a[a[u].ch[bit[i]^1]].tag>=l)
        {
            res|=(1ll<<(31-i));
            u=a[u].ch[bit[i]^1];
        }
        else
            u=a[u].ch[bit[i]];
    }
    pos=a[u].id;
    return res;
}

int main()
{
    int i,u;
    ll x,v;
    n=read(),m=read();
    sum[0]=0;
    insert(rt[0],0,0);
    for (i=1;i<=n;i++)
    {
        x=read();
        sum[i]=sum[i-1]^x;
        div(sum[i]);
        v=query(0,i-1,u);
        q.push((data){0,i-1,v,u,i});
        insert(rt[i],rt[i-1],i);
    }
    data c;
    while (m--)
    {
        c=q.top();
        q.pop();
        ans+=c.val;
        div(sum[c.id]);
        if (c.l<c.pos)
        {
            v=query(c.l,c.pos-1,u);
            q.push((data){c.l,c.pos-1,v,u,c.id});
        }
        if (c.pos<c.r)
        {
            v=query(c.pos+1,c.r,u);
            q.push((data){c.pos+1,c.r,v,u,c.id});
        }
    }
    printf("%lld\n",ans);
    return 0;
}
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!