bzoj 5495: [2019省队联测]异或粽子【可持久化trie+大根堆】

和bzoj4504差不多,就是换了个数据结构
像超级钢琴一样把五元组放进大根堆,每次取一个出来拆开,(d,l,r,p,v)表示右端点为d,左端点区间为(l,r),最大区间和值为v左端点在p上
关于怎么快速求区间和,用一个可持久trie上维护最大xor值和对应的点即可

#include<iostream>
#include<cstdio>
#include<queue>
//#include<ctime>
using namespace std;
const int N=500005;
int n,m,rt[N],tot;
unsigned int a[N],s[N],b[35];
long long ans;
struct trie
{
    int c[2],s,p;
}t[20000005];
struct qwe
{
    int d,l,r,p;
    unsigned int v;
    qwe(int D=0,int L=0,int R=0,int P=0,unsigned int V=0)
    {
        d=D,l=L,r=R,p=P,v=V;
    }
    bool operator < (const qwe &a) const
    {
        return v<a.v;
    }
};
priority_queue<qwe>q;
long long read()
{
    long long r=0,f=1;
    char p=getchar();
    while(p>'9'||p<'0')
    {
        if(p=='-')
            f=-1;
        p=getchar();
    }
    while(p>='0'&&p<='9')
    {
        r=r*10+p-48;
        p=getchar();
    }
    return r*f;
}
void ins(int &ro,int la,int w,int id)
{
    ro=++tot;
    t[ro]=t[la];
    t[ro].s++;
    if(w==-1)
    {
        t[ro].p=id;
        return;
    }
    bool p=(s[id]&b[w]);//cerr<<w<<" "<<p<<endl;
    ins(t[ro].c[p],t[la].c[p],w-1,id);
}
pair<int,unsigned int>ques(int la,int ro,int id,int w,unsigned int v)
{//cerr<<t[ro].s-t[la].s<<endl;
    if(w==-1)
        return make_pair(t[ro].p,v);
    bool p=(s[id]&b[w]);//cerr<<w<<" "<<p<<" "<<t[t[ro].c[p^1]].s<<" "<<t[t[la].c[p^1]].s<<endl;
    if(t[t[ro].c[p^1]].s-t[t[la].c[p^1]].s>0)
        return ques(t[la].c[p^1],t[ro].c[p^1],id,w-1,v|b[w]);
    else
        return ques(t[la].c[p],t[ro].c[p],id,w-1,v);
}
int main()
{
    // freopen("xor.in","r",stdin);
    // freopen("xor.out","w",stdout);
    n=read(),m=read();
    for(int i=1;i<=n;i++)
        a[i]=read();
    b[0]=1;
    for(int i=1;i<=31;i++)
        b[i]=(b[i-1]<<1);
    for(int i=n;i>=1;i--)
        s[i]=s[i+1]^a[i];
    rt[0]=++tot;
    for(int i=1;i<=n;i++)
        ins(rt[i],rt[i-1],31,i);//cerr<<"OK"<<endl;
    for(int i=1;i<=n;i++)
    {
        pair<int,unsigned int>nw=ques(rt[0],rt[i],i+1,31,0);
        q.push(qwe(i,1,i,nw.first,nw.second));
    }
    while(m--)
    {
        qwe u=q.top();//cerr<<u.v<<endl;
        q.pop();
        ans+=u.v;
        if(u.l<=u.p-1)
        {
            pair<int,unsigned int>nw=ques(rt[u.l-1],rt[u.p-1],u.d+1,31,0);
            q.push(qwe(u.d,u.l,u.p-1,nw.first,nw.second));
        }
        if(u.p+1<=u.r)
        {
            pair<int,unsigned int>nw=ques(rt[u.p],rt[u.r],u.d+1,31,0);
            q.push(qwe(u.d,u.p+1,u.r,nw.first,nw.second));
        }
    }//cerr<<clock()<<endl;
    printf("%lld\n",ans);
    return 0;
}

转载于:https://www.cnblogs.com/lokiii/p/10712165.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值