Luogu3613 睡觉困难综合征

luogu题面
这道题是NOI起床困难综合症改编而来的
思路是一样的
这道题我们考虑用LCT维护,每个节点维护两个值
一个为中序遍历这棵子树的ans0,ans1(分别表示0和INF(二进制下全为1)跑的答案)
另一个为中序遍历的反向遍历这棵子树的ans0,ans1
还要记得保存这个点的初始操作

考虑合并,若知道的左边的f0,f1,右边的g0,g1,合并后的h0,h1 有
h0 = (~f0 & g0) | (f0 & g1)
h1 = (~f1 & g0) | (f1 & g1)
含义就是走完前面,是0的继续走0,不是的走1

注意LCT中Splay区间翻转时交换左右

最后按高位贪心跑一遍


# include <bits/stdc++.h>
# define RG register
# define IL inline
# define Fill(a, b) memset(a, b, sizeof(a))
using namespace std;
typedef long long ll;
typedef unsigned long long ul;
const int _(1e5 + 10);

IL ul Read(){
    char c = '%'; ul x = 0, z = 1;
    for(; c > '9' || c < '0'; c = getchar()) if(c == '-') z = -1;
    for(; c >= '0' && c <= '9'; c = getchar()) x = x * 10 + c - '0';
    return x * z;
}

int n, m, fa[_], ch[2][_], rev[_], S[_];
struct Value{  ul f0, f1;  } G, val[_], lr[_], rl[_];

IL Value Merge(RG Value X, RG Value Y){
    G.f0 = (~X.f0 & Y.f0) | (X.f0 & Y.f1);
    G.f1 = (~X.f1 & Y.f0) | (X.f1 & Y.f1);
    return G;
}

IL bool Son(RG int x){  return ch[1][fa[x]] == x;  }

IL bool Isroot(RG int x){  return ch[0][fa[x]] != x && ch[1][fa[x]] != x;  }

IL void Update(RG int x){
    lr[x] = rl[x] = val[x];
    if(ch[0][x]) lr[x] = Merge(lr[ch[0][x]], lr[x]), rl[x] = Merge(rl[x], rl[ch[0][x]]);
    if(ch[1][x]) lr[x] = Merge(lr[x], lr[ch[1][x]]), rl[x] = Merge(rl[ch[1][x]], rl[x]);
}

IL void Reverse(RG int x){  swap(lr[x], rl[x]); swap(ch[0][x], ch[1][x]); rev[x] ^= 1;  }

IL void Pushdown(RG int x){  if(!rev[x]) return; Reverse(ch[0][x]); Reverse(ch[1][x]); rev[x] = 0;  }

IL void Rotate(RG int x){
    RG int y = fa[x], z = fa[y], c = Son(x);
    if(!Isroot(y)) ch[Son(y)][z] = x; fa[x] = z;
    ch[c][y] = ch[!c][x]; fa[ch[c][y]] = y;
    ch[!c][x] = y; fa[y] = x;
    Update(y);
}

IL void Splay(RG int x){
    S[++S[0]] = x;
    for(RG int y = x; !Isroot(y); y = fa[y]) S[++S[0]] = fa[y];
    while(S[0]) Pushdown(S[S[0]--]);
    for(RG int y = fa[x]; !Isroot(x); Rotate(x), y = fa[x])
        if(!Isroot(y)) Son(x) ^ Son(y) ? Rotate(x) : Rotate(y);
    Update(x);
}

IL void Access(RG int x){  for(RG int y = 0; x; y = x, x = fa[x]) Splay(x), ch[1][x] = y, Update(x);  }

IL void Makeroot(RG int x){  Access(x); Splay(x); Reverse(x);  }

IL void Split(RG int x, RG int y){  Makeroot(x); Access(y); Splay(y);  }

IL void Link(RG int x, RG int y){  Makeroot(x); fa[x] = y;  }

IL ul Query(RG int x, RG int y, RG ul z){
    RG ul ans = 0, t = 1; Split(x, y);
    for(RG int k = 63; k >= 0; k--)
        if(lr[y].f0 & (t << k)) ans += (t << k);
        else if(lr[y].f1 & (t << k) && z >= (t << k)) z -= (t << k), ans += (t << k);
    return ans;
}

int main(RG int argc, RG char *argv[]){
    n = Read(); m = Read(); Read(); RG ul e = 0;
    for(RG int i = 1; i <= n; i++){
        RG int x = Read(); RG ul y = Read();
        if(x == 1) val[i] = (Value){e, y};
        if(x == 2) val[i] = (Value){y, ~e};
        if(x == 3) val[i] = (Value){y, ~y};
    }
    for(RG int i = 1, x, y; i < n; i++) x = Read(), y = Read(), Link(x, y);
    while(m--){
        RG ul op = Read(), i = Read(), x = Read(), y = Read();
        if(op == 1) printf("%llu
", Query(i, x, y));
        else{
            if(x == 1) val[i] = (Value){e, y};
            if(x == 2) val[i] = (Value){y, ~e};
            if(x == 3) val[i] = (Value){y, ~y};
            Splay(i);
        }
    }
    return 0;
}
原文地址:https://www.cnblogs.com/cjoieryl/p/8206340.html