(color{#0066ff}{ 题目描述 })
由乃这个问题越想越迷糊,已经达到了废寝忘食的地步。结果她发现……晚上睡不着了!只能把自己的一个神经元(我们可以抽象成一个树形结构)拿出来,交给Deus。
这个神经元是一个有n个点的树,每个点的包括一个位运算opt和一个权值x,位运算有&,l,^三种,分别用1,2,3表示。
为了治疗失眠,Deus可以将一些神经递质放在点x上,初始的刺激值是(v_0)。然后v依次经过从x到y的所有节点,每经过一个点i,v就变成v opti xi,所以他想问你,最后到y时,希望得到的刺激值尽可能大,所以最大值的v可以是多少呢?当然由于初始的神经递质的量有限,所以给定的初始值(v_0)必须是在[0,z]之间。Deus每次都会给你3个数,x,y,z。
不过,Deus为了提升治疗效果,可能会对一些神经节点进行微调。在这种情况下,也会给三个数x,y,z,意思是把x点的操作修改为y,数值改为z
(color{#0066ff}{输入格式})
第一行三个数n,m,k。k的意义是每个点上的数,以及询问中的数值z都 (<2^k)。之后n行,每行两个数x,y表示该点的位运算编号以及数值
之后n - 1行,每行两个数x,y表示x和y之间有边相连
之后m行,每行四个数,Q,x,y,z表示这次操作为Q(1位询问,2为更改),x,y,z意义如题所述
(color{#0066ff}{输出格式})
对于每个操作1,输出到最后可以造成的最大刺激度v
(color{#0066ff}{输入样例})
5 5 3
1 7
2 6
3 7
3 6
3 1
1 2
2 3
3 4
1 5
1 1 4 7
1 1 3 5
2 1 1 3
2 3 3 3
1 1 3 2
2 2 2
2 2
2 2
1 2
2 2 2 2
1 2 2 2
(color{#0066ff}{输出样例})
7
1
5
3
(color{#0066ff}{数据范围与提示})
对于30%的数据,n,m <= 1
对于另外20%的数据,k <= 5
对于另外20%的数据,位运算只会出现一种
对于100%的数据,0 <= n , m <= 100000 , k <= 64
(color{#0066ff}{ 题解 })
位运算神仙题qwq
要一种支持单点修改,树链查询的东东维护,就LCT啦
要使最后结果最大,显然可以按位贪心
用0跑一边,用1跑一边,再根据给的范围,看当前位那个更优
这样应该可以拿到50pts
其实发现,可以所有一起跑
即64个二进制位,全是0跑出来的结果和全是1跑出来的结果,到最后再贪心
因为LCT的Splay有翻转这种东西,而对于(x-y),从y到x和从x到y的结果是不一定相同的!
因此我们要记录两个值, 一个是从左到右用全0和全1跑出来的值,一个是从右到左用全0和全1跑出来的值
假设我们已经知道了两个区间的值,如何合并呢
设左边的为f0,f1右边的为g0,g1,合并后的结果为h0,h1
那么有
h0=(~f0&g0)+(f0&g1)
h1=(~f1&g0)+(f1&g1)
这是个啥东西。。。
全0通过左区间之后,就是f0,考虑里面1的贡献和0的贡献。
0的贡献即g0通过后有1的位置,但是要合并还得满足从f0通过是0,因此把f0取反在按位与一下
就是说只有那些通过左区间为0的位置,经过g0为1,才会产生贡献
1就同理啦
再同理一下,h1也是这样的,然后就直接LCT维护即可了
#include<bits/stdc++.h>
#define LL unsigned long long
LL in() {
char ch; LL x = 0, f = 1;
while(!isdigit(ch = getchar()))(ch == '-') && (f = -f);
for(x = ch ^ 48; isdigit(ch = getchar()); x = (x << 1) + (x << 3) + (ch ^ 48));
return x * f;
}
const int maxn = 1e5 + 10;
struct bit {
LL f0, f1;
bit(LL f0 = 0, LL f1 = 0): f0(f0), f1(f1) {}
friend bit operator + (const bit &a, const bit &b) {
return bit((~a.f0 & b.f0) | (a.f0 & b.f1), (~a.f1 & b.f0) | (a.f1 & b.f1));
}
};
LL f[maxn];
struct node {
node *ch[2], *fa;
bit f, l, r;
int rev;
node(int rev = 0): rev(rev) { ch[1] = ch[0] = fa = NULL; }
void trn() { std::swap(ch[0], ch[1]), std::swap(l, r), rev ^= 1; }
void upd() {
l = r = f;
if(ch[0]) l = ch[0]->l + l, r = r + ch[0]->r;
if(ch[1]) l = l + ch[1]->l, r = ch[1]->r + r;
}
void dwn() {
if(!rev) return;
if(ch[0]) ch[0]->trn();
if(ch[1]) ch[1]->trn();
rev = 0;
}
bool isr() { return this == fa->ch[1]; }
bool ntr() { return fa && (fa->ch[0] == this || fa->ch[1] == this); }
}pool[maxn];
struct EDGE {
int to;
EDGE *nxt;
EDGE(int to = 0, EDGE *nxt = NULL): to(to), nxt(nxt) {}
}*head[maxn];
void rot(node *x) {
node *y = x->fa, *z = y->fa;
bool k = x->isr(); node *w = x->ch[!k];
if(y->ntr()) z->ch[y->isr()] = x;
(x->ch[!k] = y)->ch[k] = w;
(y->fa = x)->fa = z;
if(w) w->fa = y;
y->upd(), x->upd();
}
void splay(node *o) {
static node *st[maxn];
int top;
st[top = 1] = o;
while(st[top]->ntr()) st[top + 1] = st[top]->fa, top++;
while(top) st[top--]->dwn();
while(o->ntr()) {
if(o->fa->ntr()) rot(o->isr() ^ o->fa->isr()? o : o->fa);
rot(o);
}
}
void access(node *x) {
for(node *y = NULL; x; x = (y = x)->fa)
splay(x), x->ch[1] = y, x->upd();
}
void makeroot(node *x) { access(x), splay(x), x->trn(); }
void split(node *x, node *y) { makeroot(x), access(y), splay(y); }
void add(int from, int to) {
head[from] = new EDGE(to, head[from]);
}
void dfs(int x, int fa) {
for(EDGE *i = head[x]; i; i = i->nxt) {
if(i->to == fa) continue;
pool[i->to].fa = pool + x;
dfs(i->to, x);
}
}
int n, m, k;
int main() {
n = in(), m = in(), k = in();
for(int i = 1; i <= n; i++) {
int p = in(); LL x = in();
if(p == 1) pool[i].f = bit(0, x);
if(p == 2) pool[i].f = bit(x, ~0);
if(p == 3) pool[i].f = bit(x, ~x);
}
int x, y;
for(int i = 1; i < n; i++) x = in(), y = in(), add(x, y), add(y, x);
dfs(1, 0);
while(m --> 0) {
int p = in(), x = in(), y = in(); LL val = in();
if(p & 1) {
split(pool + x, pool + y);
LL ans = 0, o = 1;
for(int i = k - 1; i >= 0; i--) {
if(pool[y].l.f0 & (o << i)) ans |= (o << i);
else if((pool[y].l.f1 & (o << i)) && val >= (o << i)) val ^= (o << i), ans |= (o << i);
}
printf("%llu
", ans);
}
else {
if(y == 1) pool[x].f = bit(0, val);
if(y == 2) pool[x].f = bit(val, ~0);
if(y == 3) pool[x].f = bit(val, ~val);
splay(pool + x);
}
}
return 0;
}