zoukankan      html  css  js  c++  java
  • 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
    ", 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;
    }
    
  • 相关阅读:
    RSS Reader in PC & iPhone
    Implementation Notes: Runtime Environment Map Filtering for Image Based Lighting
    A implementaion for 2D blue noise
    Specular Aliasing与Specular Leaking
    PBR Metallic/Roughness工作流中Albedo与F0的计算方法
    Mathematica .nb程序运行不下去的原因
    关于ddx/ddy重建法线在edge边沿上的artifacts问题
    make: 警告:检测到时钟错误。您的创建可能是不完整的。
    C++ 变长模板参数
    CMake set 语法
  • 原文地址:https://www.cnblogs.com/olinr/p/10398100.html
Copyright © 2011-2022 走看看