Qiuly

「十二省联考2019」异或粽子 可持久化Trie树 luoguP5283
要是我不是 $\texttt{HN}$ 的该多好,今年十二省联考两道傻逼题,一道异或粽子,一道十二响......[...
扫描右侧二维码阅读全文
24
2019/05

「十二省联考2019」异或粽子 可持久化Trie树 luoguP5283

要是我不是 $\texttt{HN}$ 的该多好,今年十二省联考两道傻逼题,一道异或粽子,一道十二响......

[十二省联考2019]异或粽子,可持久化 $trie$ 树的板子题,比最大异或和还要板子些。相信 $60$ 分入门者都会做,那么 $100$ 分的话我们上可持久化 $trie$ 树维护前缀异或和,嗯没错就像主席树那样。然后对于每个节点的可持久化 $trie$ 树我们将其当成区间右端点,然后在此位置上的 $trie$ 树中贪心寻找左端点即可。

寻找前 $K$ 大区间的具体操作如下:

for(ll i=1;i<=n;++i) 
    q.push(MKP(T.query(T.root[i],sum[i],qrank[i]=1),i));
/*对于每一个右端点,找一个第一大(最优)的左端点放入优先队列*/
ll ans=0;
while(k--) {
    ll i=q.top().second;/*取出当前最优元素*/
    ans+=q.top().first;q.pop();
    if(qrank[i]!=i) q.push(MKP(T.query(T.root[i],sum[i],++qrank[i]),i));
    /*更新队列元素*/
}

复杂度大约是 $O(nlogn)$ 级别。

Code:

#include <queue>
#include <cstdio>
#include <string>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long ll;
#define MKP make_pair

const ll N=5e5+2;
const ll logN=33;
const ll inf=1e9+9;

template <typename _Tp> inline void IN(_Tp&x) {
    char ch;bool flag=0;x=0;
    while(ch=getchar(),!isdigit(ch)) if(ch=='-') flag=1;
    while(isdigit(ch)) x=x*10+ch-'0',ch=getchar();
    if(flag) x=-x;
}

ll n,k,sum[N],qrank[N];
priority_queue<pair<ll,ll> > q;

struct Trie {
    ll ch[N*logN][2],sum[N*logN],root[N],tot;
    ll newnode(ll x) {
        ++tot,ch[tot][0]=ch[x][0],ch[tot][1]=ch[x][1];
        sum[tot]=sum[x];return tot;
    }
    void Insert(ll&rt,ll val) {
        rt=newnode(rt),++sum[rt];
        ll now=rt;
        for(ll i=31;~i;--i) {
            bool son=(val>>i)&1;
            ch[now][son]=newnode(ch[now][son]);
            now=ch[now][son],++sum[now];
        }return;
    }
    ll query(ll now,ll val,ll k) {
        ll ans=0;
        for(ll i=31;~i;--i) {
            bool son=!((val>>i)&1);
            if(k<=sum[ch[now][son]]) now=ch[now][son],ans|=(1u<<i);
            else k-=sum[ch[now][son]],now=ch[now][!son];
        }return ans;
    }
}T;

int main(){
    IN(n),IN(k);
    for(ll i=1,x;i<=n;++i) IN(x),sum[i]=sum[i-1]^x;
    for(ll i=0;i<=n;++i) {
        if(i) T.root[i]=T.root[i-1];
        T.Insert(T.root[i],sum[i]);
    }
    for(ll i=1;i<=n;++i) 
        q.push(MKP(T.query(T.root[i],sum[i],qrank[i]=1),i));
    ll ans=0;
    while(k--) {
        ll i=q.top().second;
        ans+=q.top().first;q.pop();
        if(qrank[i]!=i) q.push(MKP(T.query(T.root[i],sum[i],++qrank[i]),i));
    }
    printf("%lld\n",ans);
    return 0;
}
最后修改:2019 年 05 月 30 日 03 : 23 PM

发表评论