P5283 [十二省联考2019]异或粽子

传送门

超级钢琴+可持久化$Trie$

同样设三元组 $(o,l,r)$ 表示左端点为 $o$,右端点 $\in [l,r]$ 的区间的最大异或值,这个东西可以用可持久化 $Trie$ 来维护

一开始把所有 $(i,i,n)$ 扔到堆里,然后每次取出计算贡献,设取得最大异或值的位置为 $t$,然后再把 $(o,l,t-1)$ 和 $(o,t+1,r)$ 扔到堆里

具体还是看代码,很容易理解

注意可能爆 $int$,所以要开 $unsigned\ int$,要注意代码常数,我代码 $luogu$ 上会 $TLE$,$LOJ$ 就可以过

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<queue>
using namespace std;
typedef long long ll;
typedef unsigned int uint;
inline uint read()
{
    uint x=0; char ch=getchar();
    while(ch<'0'||ch>'9') ch=getchar();
    while(ch>='0'&&ch<='9') { x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); }
    return x;
}
const int N=1e6+7,M=1e7+7e6;
uint n,K,sum[N],rt[N],t[M],pos[M],c[M][2];
namespace Trie {
    uint cnt=0;
    void ins(uint &o,int p,uint pre,uint v,uint ps)
    {
        o=++cnt; t[o]=t[pre]+1;
        if(p<0) { pos[o]=ps; return; }
        int d=(v>>p)&1; c[o][d^1]=c[pre][d^1];
        ins(c[o][d],p-1,c[pre][d],v,ps);
    }
    uint query(uint o,int p,uint pre,uint v)
    {
        if(p<0) return pos[o];
        int d=(v>>p)&1;
        if(t[c[o][d^1]]-t[c[pre][d^1]]>0) return query(c[o][d^1],p-1,c[pre][d^1],v);
        else return query(c[o][d],p-1,c[pre][d],v);
    }
}
struct dat {
    uint o,l,r,t;
    dat (uint o,uint l,uint r) : o(o),l(l),r(r),t(Trie::query(rt[r],31,rt[l-1],sum[o-1])) {}
    inline bool operator < (const dat &tmp) const {
        return (sum[t]^sum[o-1])<(sum[tmp.t]^sum[tmp.o-1]);
    }
};
priority_queue <dat> Q;
ll ans;
int main()
{
    n=read(),K=read(); uint a;
    Trie::ins(rt[0],31,0,0,0);
    for(int i=1;i<=n;i++)
    {
        a=read(); sum[i]=sum[i-1]^a;
        Trie::ins(rt[i],31,rt[i-1],sum[i],i);
    }
    for(int i=1;i<=n;i++) Q.push(dat(i,i,n));
    while(K--)
    {
        dat T=Q.top(); ans+=(sum[T.t]^sum[T.o-1]); Q.pop();
        if(T.l<T.t) Q.push(dat(T.o,T.l,T.t-1));
        if(T.r>T.t) Q.push(dat(T.o,T.t+1,T.r));
    }
    cout<<ans<<endl;
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/LLTYYC/p/10682774.html