Codeforces Round #430 (Div. 2) Vitya and Strange Lesson

D、Vitya and Strange Lesson(字典树)

题意:

给一个长度为(n)的非负整数序列,(m)次操作,每次先全局异或(x),再查询(mex)
(1<=n<=3e5)
(0<=a_i<=3e5)
(0<=x<=3e5)

思路:求(mex)可以通过按从高位到低位建字典树,判断左子树是否满,若未满,贪心往走,否则往右走,这样查询是(log)
现在就是异或修改,考虑x的第i位,若为1,则以第i-1层结点为根的左右子树都需要交换
如果每次暴力修改所有是会超时的,使用线段树区间更新那样的技巧,要查询某段区间的时候再做更新。
所以用打标记的方法下传就好了

#include<bits/stdc++.h>
#define LL long long
#define P pair<int,int>
#define ls(i) seg[i].lc
#define rs(i) seg[i].rc
using namespace std;

void read(int &x){
    char c = getchar();
    x = 0;
    while(c < '0' || c > '9') c = getchar();
    while(c >= '0' && c <= '9') x = x * 10 + c - '0',c = getchar();
}
const int N = 3e5 + 10;

int base[20];
struct T{
    int lc,rc,cnt,col;
}seg[N * 25];
int tot,root;
void Insert(int &rt,int x,int dep){
    if(!rt) rt = ++tot;
    if(dep == 0){
        seg[rt].cnt = 1;
        return ;
    }
    if(x & base[dep - 1]) Insert(rs(rt),x,dep - 1);
    else Insert(ls(rt),x,dep - 1);
    seg[rt].cnt = seg[ls(rt)].cnt && seg[rs(rt)].cnt;
}
void pushdown(int rt,int dep){
    if(dep < 0) return ;
    int col = seg[rt].col;
    seg[ls(rt)].col ^= col, seg[rs(rt)].col ^= col;
    if(col & base[dep]) swap(seg[rt].lc,seg[rt].rc);
    seg[rt].col = 0;
}
int query(int rt,int dep){
    if(dep == 0) return 0;
    pushdown(rt,dep - 1);
    if(!seg[ls(rt)].cnt) return query(ls(rt),dep - 1);///左子树未满,高位到低位尽量往左边走
    else return query(rs(rt),dep - 1) + base[dep - 1];///只能往右走
}
int main(){

    int x,n,m;
    read(n),read(m);
    tot = root = 0;
    base[0] = 1;
    for(int i = 1;i <= 20;i++) base[i] = base[i-1] * 2;
    for(int i = 1;i <= n;i++){
        read(x);
        Insert(root,x,20);
    }
    while(m--){
        read(x);
        seg[root].col ^= x;
        printf("%d
",query(root,20));
    }
    return 0;
}


原文地址:https://www.cnblogs.com/jiachinzhao/p/7453529.html