可持久化Trie

咕了两天的内容

和主席树的思想差不多,当前节点有的边就往下连,没有的边就连到之前的trie上

 

最大异或和:https://www.luogu.org/problem/P4735

处理前缀异或和,则问题为求p在[l - 1,r - 1]内,s[p] ^ (s[n] ^ x)的最大值

考虑到右边是定值,转化为求区间内异或定值的最大值,可持久化Trie板子

细节看代码

// luogu-judger-enable-o2
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<queue>
#include<map>
using namespace std;
typedef long long ll;
typedef double db;
#define llinf 9000000000000000000LL
#define B cout << "breakpoint" << endl;
#define O(x) cout << #x << "  "  << x << endl;
inline int read()
{
    int ans = 0,op = 1;
    char ch = getchar();
    while(ch < '0' || ch > '9')
    {
        if(ch == '-') op = -1; 
        ch = getchar();
    }
    while(ch >= '0' && ch <= '9')
    {
        (ans *= 10) += ch - '0';
        ch = getchar();
    }
    return ans * op;
}
const int maxn = 6e5 + 5;
int sum[maxn],tot;
int ch[maxn * 27][2],cnt[maxn * 27],rt[maxn];
void insert(int a,int b,int t,int x)
{
    if(t < 0) return;
    int i = (x >> t) & 1;
    ch[a][!i] = ch[b][!i];
    ch[a][i] = ++tot;
    cnt[ch[a][i]] = cnt[ch[b][i]] + 1;
    insert(ch[a][i],ch[b][i],t - 1,x);
}
int query(int a,int b,int t,int x)
{
    if(t < 0) return 0;
    int i = (x >> t) & 1;
    if(cnt[ch[b][!i]] - cnt[ch[a][!i]] > 0)
        return (1 << t) + query(ch[a][!i],ch[b][!i],t - 1,x);
    else return query(ch[a][i],ch[b][i],t - 1,x);
}
int n,m;
int main()
{
    char op[5];
    int x,l,r;
    n = read(),m = read();
    rt[0] = ++tot;
    insert(rt[0],0,25,0);
    for(int i = 1;i <= n;i++)
    {
        x = read();
        sum[i] = sum[i - 1] ^ x;
        rt[i] = ++tot;
        insert(rt[i],rt[i - 1],25,sum[i]);
    }
    while(m--)
    {
        scanf("%s",op);
        if(op[0] == 'A')
        {
            x = read();
            n++;
            sum[n] = sum[n - 1] ^ x;
            rt[n] = ++tot;
            insert(rt[n],rt[n - 1],25,sum[n]);
        }
        else
        {
            l = read(),r = read(),x = read();
            l--,r--;
            if(l == 0) printf("%d\n",query(0,rt[r],25,x ^ sum[n]));
            else printf("%d\n",query(rt[l - 1],rt[r],25,x ^ sum[n]));
        }
    }
}
View Code

 

异或粽子:https://www.luogu.org/problem/P5283

时隔好久2333

依旧套路处理前缀异或和,然后考虑固定右端点求出每个右端点最大值,放入堆中

维护一个堆,每次把当前K大值取出来,加入答案,再向堆中扔入K+1大值

如何求区间内异或定值的K大值也是板子,细节在代码

// luogu-judger-enable-o2
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<queue>
#include<map>
using namespace std;
typedef long long ll;
typedef int mainint;
#define int long long
typedef double db;
#define pii pair<int,int>
#define mp make_pair
#define llinf 9000000000000000000LL
#define B cout << "breakpoint" << endl;
#define O(x) cout << #x << "  "  << x << endl;
inline int read()
{
    int ans = 0,op = 1;
    char ch = getchar();
    while(ch < '0' || ch > '9')
    {
        if(ch == '-') op = -1; 
        ch = getchar();
    }
    while(ch >= '0' && ch <= '9')
    {
        (ans *= 10) += ch - '0';
        ch = getchar();
    }
    return ans * op;
}
const int maxn = 6e5 + 5;
int sum[maxn],tot;
int ch[maxn * 40][2],cnt[maxn * 40],rt[maxn],num[maxn];
int n,k;
void insert(int a,int b,int t,int x)
{
    if(t < 0) return;
    int i = (x >> t) & 1;
    ch[a][!i] = ch[b][!i];
    ch[a][i] = ++tot;
    cnt[ch[a][i]] = cnt[ch[b][i]] + 1;
    insert(ch[a][i],ch[b][i],t - 1,x);
}
int query(int a,int b,int t,int x,int num)
{
    if(t < 0) return 0;
    int i = (x >> t) & 1;
    int tp = cnt[ch[b][!i]] - cnt[ch[a][!i]];
    if(tp >= num)
        return (1ll << t) + query(ch[a][!i],ch[b][!i],t - 1,x,num);
    else return query(ch[a][i],ch[b][i],t - 1,x,num - tp);
}
mainint main()
{
    ll ans = 0;
    n = read(),k = read();
    rt[0] = ++tot;
    insert(rt[0],0,34,0);
    for(int i = 1;i <= n;i++)
    {
        int x = read();
        sum[i] = sum[i - 1] ^ x;
        rt[i] = ++tot;
        insert(rt[i],rt[i - 1],34,sum[i]);
        num[i] = 1;
    }
    priority_queue<pii> q;
    for(int i = 1;i <= n;i++) q.push(mp(query(0,rt[i - 1],34,sum[i],num[i]),i));
    for(int i = 1;i <= k;i++)
    {
        int u = q.top().second;
        ans += q.top().first;
        q.pop();
        num[u]++;
        q.push(mp(query(0,rt[u - 1],34,sum[u],num[u]),u));
    }
    printf("%lld",ans);
}
View Code

 

posted on 2019-07-26 21:52  L_M_A  阅读(104)  评论(0编辑  收藏  举报

导航