bzoj3261(可持久化字典树)

Description
给定一个非负整数序列{a},初始长度为N。
有M个操作,有以下两种操作类型:
1、Ax:添加操作,表示在序列末尾添加一个数x,序列的长度N+1。
2、Qlrx:询问操作,你需要找到一个位置p,满足l<=p<=r,使得:
a[p] xor a[p+1] xor … xor a[N] xor x 最大,输出最大是多少。
Input
第一行包含两个整数 N ,M,含义如问题描述所示。
第二行包含 N个非负整数,表示初始的序列 A 。
接下来 M行,每行描述一个操作,格式如题面所述。

Output
假设询问操作有 T个,则输出应该有 T行,每行一个整数表示询问的答案。

Sample Input
5 5
2 6 4 3 6
A 1
Q 3 5 4
A 4
Q 5 7 0
Q 3 6 6
对于测试点 1-2,N,M<=5 。
对于测试点 3-7,N,M<=80000 。
对于测试点 8-10,N,M<=300000 。
其中测试点 1, 3, 5, 7, 9保证没有修改操作。
0<=a[i]<=10^7。
Sample Output
4
5


可持久化0/1trie模板吧….
有一个WA点,直接建的话相当于查 l2 l − 2 ~ r1 r − 1
一开始没处理,最好是在开头插个0

#include<bits/stdc++.h>
using namespace std;
#define rep(i,j,k) for(int i = j;i <= k;++i)
#define repp(i,j,k) for(int i = j;i >= k;--i)
#define rept(i,x) for(int i = linkk[x];i;i = e[i].n)
#define P pair<int,int>
#define Pil pair<int,ll>
#define Pli pair<ll,int>
#define Pll pair<ll,ll>
#define pb push_back 
#define pc putchar
#define file(k) memset(k,0,sizeof(k))
#define ll long long
#define N 600000
int n , q , totr;
int root[N+1] , a[N+1];
struct trie{
    int tot;
    int tr[N*24+5][2] , sum[N*24+5];
    int insert(int root,int last,int val)
    {
        int tmp = root = ++tot;
        repp(i,23,0)
        {
            tr[root][0] = tr[last][0];tr[root][1] = tr[last][1];
            sum[root] = sum[last] + 1;
            int k = (val>>i)&1;
            tr[root][k] = ++tot;
            root = tr[root][k];
            last = tr[last][k];
        }
        sum[root] = sum[last] + 1;
        return tmp;
    }
    int query(int x,int y,int val)
    {
        int ans = 0;
        repp(i,23,0)
        {
            int k = (val>>i)&1;
            if(sum[tr[y][k^1]] - sum[tr[x][k^1]])
                ans += 1<<i,
                x = tr[x][k^1],
                y = tr[y][k^1];
            else x = tr[x][k] , y = tr[y][k];
        }
        return ans;
    }
}trie;
int read()
{
    int sum = 0;char c = getchar();bool flag = true;
    while( c < '0' || c > '9' ) {if(c == '-') flag = false;c = getchar();}
    while( c >= '0' && c <= '9' ) sum = sum * 10 + c - 48 , c = getchar();
    if(!flag)  sum = -sum;
    return sum;
} 
void init()
{
    n = read();q = read();
    root[1] = trie.insert(root[1],root[0],0);
    rep(i,2,n+1)
    {
        int x = read();
        a[i] = x ^ a[i-1];
        root[i] = trie.insert(root[i],root[i-1],a[i]);
    }
    totr = n+1;
    return;
}
int main()
{
    init();
    rep(i,1,q)
    {
        char k = getchar();
        while(k != 'A' && k != 'Q') k = getchar();
        if(k == 'A')
        {
            int x = read();
            a[++totr] = a[totr-1] ^ x;
            root[totr] = trie.insert(root[totr],root[totr-1],a[totr]);
        }
        else
        {
            int l = read() , r = read() , x = read();
            x ^= a[totr];
            printf("%d\n",trie.query(root[l-1],root[r],x));
        }
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值