羅区[P5283] XOR [餃子] [スタック]トライ

効果の件名:

トピックリンク:https://www.luogu.org/problemnew/show/P5283
見出される配列与えられました メートル メートル 間隔 [ リットル R ] [L_iを、R_iを】 このような最大間隔とXORこと。


アイデア:

問題が変換されるように、それは最初の接頭辞のXOR、見つけるために行います メートル メートル リットル R L、R その結果、 Σ リットル   x o r   r \和リットルの\ XOR \ rを できるだけ大きいです。
お知らせ a [ l ]   x o r   a [ r ] = a [ r ]   x o r   a [ l ] [L] \ XOR \ A [R]は[R] \ XOR \ [リットル] = 、選出された場合のように l , r L、R 、再度選択します r , l R、L だから我々は、回数を求めることができます × 2 \ 2倍 、各二つの連続するクエリが同じに設定されるように ( l , r ) ( r , l ) (L、R)(R、L) ライン上の2最終的な答えで割りました。
私たちは、それぞれの意志、ヒープを維持します i 、対応します a [ i ]   x o r   a [ j ] [i]は\ XOR \ A [j]は の最大 j J 、反応器、スタックの各取ら呼び掛けトップ、大次内部スロー a [ i ]   x o r   a [ j ] [i]は\ XOR \ A [j]は ヒープに投げ込ま。
以下のために x バツ を求めます y 作り a [ x ]   x o r   a [ y ] [X] \ XOR \ A [Y] 第として k K 大明らかにすることができます T r i e トライ メンテナンス。たびに左右の部分木に値を決定するために使用する権利。
だから、永続的に使用することはできません T r i e トライ この質問の完成へ。時間複雑 O ( n log n ) O(nは\ログN)


コード:

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

const int N=500010,LG=35;
int n,m,tot=1,trie[N*LG][2],cnt[N],size[N*LG];
ll a[N],ans;
priority_queue<pair<ll,int> > q;

ll read()
{
    ll d=0;
    char ch=getchar();
    while (!isdigit(ch)) ch=getchar();
    while (isdigit(ch))
        d=(d<<3)+(d<<1)+(ll)ch-48LL,ch=getchar();
    return d;
}

void insert(ll x)
{
    int p=1;
    for (int i=LG;i>=0;i--)
    {
        int id=(x>>(ll)i)&1;
        if (!trie[p][id]) trie[p][id]=++tot;
        p=trie[p][id];
        size[p]++;
    }
}

ll find(ll x,int k)
{
    int p=1; 
    ll ans=0;
    for (int i=LG;i>=0;i--)
    {
        int id=(x>>(ll)i)&1;
        if (trie[p][id^1]&&size[trie[p][id^1]]>=k)
        {
            ans=(ans<<1)|1;
            p=trie[p][id^1];
        }
        else if (trie[p][id])
        {
            k-=size[trie[p][id^1]];
         	ans<<=1;
         	p=trie[p][id];
        }
    }
    return ans;
}

int main()
{
    scanf("%d%d",&n,&m);
    insert(0); cnt[0]=1;
    for (int i=1;i<=n;i++)
    {
        a[i]=read();
        a[i]^=a[i-1];
        insert(a[i]);
        cnt[i]=1;
    }
    for (int i=0;i<=n;i++)
        q.push(mp(find(a[i],1),i));
    m*=2;
    while (m--)
    {
    	if (!q.size()) break;
        ans+=q.top().first;
        int i=q.top().second;
        q.pop();
        cnt[i]++;
        if (cnt[i]<=n+1)
            q.push(mp(find(a[i],cnt[i]),i));
    }
    cout<<ans/2LL;
    return 0;
}

おすすめ

転載: blog.csdn.net/SSL_ZYC/article/details/94644518