[bzoj5338][loj2557][TJOI2018]xor【可持久化线段树】【dfs序】【欧拉序】

【题目链接】
  https://www.lydsy.com/JudgeOnline/problem.php?id=5338
  https://loj.ac/problem/2577
【题解】
  可以开两棵可持久化权值线段树,一棵记dfs序维护子树信息,另一棵记欧拉序维护链信息。在开先段树的时候左边的二进制首位为 0 0 ,右边为 1 1
  对于一次询问,贪心向下选取就行了。
  时间复杂度 O(N31) O ( N ∗ 31 )
【代码】

# include 
# define    ll      long long
# define    ui      unsigned
# define    inf     0x3f3f3f3f
# define    N       200010
# define    K       20
using namespace std;
int read(){
    int tmp = 0, fh = 1; char ch = getchar();
    while (ch < '0' || ch > '9') {if (ch == '-') fh = -1; ch = getchar(); }
    while (ch >= '0' && ch <= '9'){tmp = tmp * 10 + ch - '0'; ch = getchar(); }
    return tmp * fh;
}
struct Edge{
    int data, next;
}e[N];
struct Tree{
    int pl, pr, size;
}T[N * 64];
int rt1[N], rt2[N], in[N], out[N], p[N], n, q, ti, head[N], place, w[N], dad[N][K + 1], dep[N];
void build(int u, int v){
    e[++place].data = v; e[place].next = head[u]; head[u] = place;
}
void dfs(int x, int fa){
    in[x] = ++ti; p[ti] = x;
    dad[x][0] = fa; dep[x] = dep[fa] + 1;
    for (int ed = head[x]; ed != 0; ed = e[ed].next)
        if (e[ed].data != fa) dfs(e[ed].data, x);
    out[x] = ++ti; p[ti] = -x;
}
void pre(){
    for (int i = 1, j = 1; j * 2 <= n; i++, j *= 2)
        for (int k = 1; k <= n; k++)
            dad[k][i] = dad[dad[k][i - 1]][i - 1];
}
int lca(int x, int y){
    if (dep[x] > dep[y]) swap(x, y);
    for (int i = K; i >= 0; i--)
        if (dep[dad[y][i]] >= dep[x])
            y = dad[y][i];
    if (x == y) return x;
    for (int i = K; i >= 0; i--)
        if (dad[y][i] != dad[x][i])
            x = dad[x][i], y = dad[y][i];
    return dad[x][0];
}
void extend(int &p, int las, int num, int tag, int k){
    p = ++place;
    T[p].size = T[las].size + tag;
    if (k >= 0){
        if ((num & (1 << k)) == 0){
            extend(T[p].pl, T[las].pl, num, tag, k - 1);
            T[p].pr = T[las].pr;
        }
        else {
            extend(T[p].pr, T[las].pr, num, tag, k - 1);
            T[p].pl = T[las].pl;
        }
    }
}
ui query1(int p1, int p2, int num, int k){
    if (k < 0) return 0;
    if ((num & (1 << k)) == 0){
        if (T[T[p1].pr].size - T[T[p2].pr].size != 0)
            return query1(T[p1].pr, T[p2].pr, num, k - 1) + (1 << k);
            else return query1(T[p1].pl, T[p2].pl, num, k - 1);
    }
    else {
        if (T[T[p1].pl].size - T[T[p2].pl].size != 0)
            return query1(T[p1].pl, T[p2].pl, num, k - 1) + (1 << k);
            else return query1(T[p1].pr, T[p2].pr, num, k - 1);
    }
}
ui query2(int p1, int p2, int p3, int p4, int num, int k){
    if (k < 0) return 0;
    if ((num & (1 << k)) == 0){
        if (T[T[p1].pr].size + T[T[p2].pr].size - T[T[p3].pr].size - T[T[p4].pr].size != 0)
            return query2(T[p1].pr, T[p2].pr, T[p3].pr, T[p4].pr, num, k - 1) + (1 << k);
            else return query2(T[p1].pl, T[p2].pl, T[p3].pl, T[p4].pl, num, k - 1);
    }
    else {
        if (T[T[p1].pl].size + T[T[p2].pl].size - T[T[p3].pl].size - T[T[p4].pl].size != 0)
            return query2(T[p1].pl, T[p2].pl, T[p3].pl, T[p4].pl, num, k - 1) + (1 << k);
            else return query2(T[p1].pr, T[p2].pr, T[p3].pr, T[p4].pr, num, k - 1);
    }
}
int main(){
//  freopen("B.in", "r", stdin);
//  freopen(".out", "w", stdout);
    n = read(), q = read();
    for (int i = 1; i <= n; i++) w[i] = read();
    for (int i = 1; i < n; i++){
        int u = read(), v = read();
        build(u, v); build(v, u);
    }
    place = 0;
    dfs(1, 0);
    for (int i = 1; i <= ti; i++){
        if (p[i] > 0){
            extend(rt1[i], rt1[i - 1], w[p[i]], 1, 30);
            extend(rt2[i], rt2[i - 1], w[p[i]], 1, 30);
        }
        else {
            rt1[i] = rt1[i - 1];
            extend(rt2[i], rt2[i - 1], w[-p[i]], -1, 30);
        }
    }
    pre();
    for (int i = 1; i <= q; i++){
        int op = read(), x, y, tmp;
        if (op == 1){
            x = read(), tmp = read();
            printf("%u\n", query1(rt1[out[x]], rt1[in[x] - 1], tmp, 30));
        }
        else {
            x = read(), y = read(), tmp = read();
            int l = lca(x, y);
            printf("%u\n", query2(rt2[in[x]], rt2[in[y]], rt2[in[l]], rt2[in[dad[l][0]]], tmp, 30));
        }
    }
    return 0;
}

你可能感兴趣的:(【可持久化线段树】,【dfs序】,【欧拉序】)