【洛谷 P4735】 最大异或和 (可持久化Trie)

题目链接
维护整个数列的异或前缀和和\(s\),然后每次就是要求\(s[N]\text{^}x\text{^}s[k],l-1<=k<=r-1\)的最大值
如果没有\(l\)的限制,那么直接用可持久化\(Trie\)查询第\(r\)个版本跑最大异或和就行。
\(Trie\)求最大异或值的方法就是把数看成二进制建树,一位位往下走能往相反的就往相反的走,不能就走相同的,走到底就是答案。
现在多了\(l\)的限制,所以需要记录每个节点在这个节点的子树中结尾的数的最大的编号是多少,记为\(latest\),每次限制只能走\(latest>=l-1\)的节点。

#include <cstdio>
#define re register
const int MAXN = 20000010;
inline int read(){
    int s = 0, w = 1;
    char ch = getchar();
    while(ch < '0' || ch > '9'){if(ch == '-')w = -1;ch = getchar();}
    while(ch >= '0' && ch <= '9') s = s * 10 + ch - '0',ch = getchar();
    return s * w;
}
int trie[MAXN][2], latest[MAXN], root[MAXN], s[MAXN];
int n, m, num;
inline int max(const int a, const int b){
    return a > b ? a : b;
}
void insert(int i, int k, int p, int q){
    if(k < 0){ latest[q] = i; return ; }
    re int c = s[i] >> k & 1;
    if(p) trie[q][c ^ 1] = trie[p][c ^ 1];
    trie[q][c] = ++num;
    insert(i, k - 1, trie[p][c], trie[q][c]);
    latest[q] = max(latest[trie[q][0]], latest[trie[q][1]]);
}
int query(int now, int val, int k, int limit){
    if(k < 0) return s[latest[now]] ^ val;
    re int c = val >> k & 1;
    if(latest[trie[now][c ^ 1]] >= limit) return query(trie[now][c ^ 1], val, k - 1, limit);
    return query(trie[now][c], val, k - 1, limit);
}
char opt;
int main(){
    n = read(); m = read();
    root[0] = ++num; latest[0] = -1;
    insert(0, 23, 0, root[0]);
    for(re int i = 1; i <= n; ++i){
       s[i] = s[i - 1] ^ read();
       root[i] = ++num;
       insert(i, 23, root[i - 1], root[i]);
    }
    for(re int i = 1, l, r, x; i <= m; ++i){
       do opt = getchar(); while(opt != 'A' && opt != 'Q');
       if(opt == 'A'){
         x = read();
         root[++n] = ++num;
         s[n] = s[n - 1] ^ x;
         insert(n, 23, root[n - 1], root[n]);
       }
       else{
         l = read(); r = read(); x = read();
         printf("%d\n", query(root[r - 1], s[n] ^ x, 23, l - 1));
       }
    }
    return 0;
}

转载于:https://www.cnblogs.com/Qihoo360/p/10315450.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值