P3613 睡觉困难综合征 LCT+贪心+位运算

\(\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

img

\(\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意义如题所述

img

\(\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\n", 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;
}
posted @ 2019-02-18 21:44  olinr  阅读(192)  评论(0编辑  收藏  举报