您的位置:首页 > 其它

Luogu3613 睡觉困难综合征

2017-12-30 09:01 316 查看
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\n", 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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: