• P3613 睡觉困难综合征(LCT + 位运算)


    题意

    NOI2014 起床困难综合症 放在树上,加上单点修改与链上查询。

    题解

    类似于原题,我们只需要求出 (0)(2^{k - 1} - 1) 走过这条链会变成什么值,就能确定每一位为 (0 / 1) 走完后变成什么值。

    我们对于 (LCT) 每个节点维护两个值 (r_0,r_1) 表示 (0)(2 ^ k - 1) 从当前 (LCT) 维护的链底走到这个点会变成什么值。

    然后我们就可以把位运算操作变成一个值放在这个点上。

    合并信息的时候,可以这样写:

    inline Data operator + (const Data &lhs, const Data &rhs) {
    	return (Data) {
    		(~lhs.r0 & rhs.r0) | (lhs.r0 & rhs.r1),
    		(~lhs.r1 & rhs.r0) | (rhs.r1 & lhs.r1)
    	};
    }
    

    此处 (sim) 是取反,也就是所有位反转,注意此处需要用 unsigned long long 存,就没有符号位,不会进行反转。

    解释前面那个地方 (~lhs.r0 & rhs.r0) 意味着最开始从 (0) 开始走,走完左子树后还是 (0) 然后继续走 得到的结果,

    (lhs.r0 & rhs.r1) 就是一开始从 (0) 走,走完左子树后变成 (1) 然后继续走 得到的结果。

    另外一个也是同理了,只是最开始从 (1) 走。

    但是这样还是不够的,因为位运算是有顺序的,(reverse) 的时候答案就会错误,所以我们多存一个逆向的值就行了。

    最后只需要像原题按位贪心就行了。

    复杂度是 (O(n + q (log n + k))) 的。

    总结

    位运算时需要对所有位进行翻转可以用 (sim) ,十分方便。

    (LCT) 维护信息如果有顺序的话,那么需要维护一个逆向操作的答案才行。

    代码

    具体可以看看代码实现(虽然写的有点长。。)

    #include <bits/stdc++.h>
    
    #define For(i, l, r) for(register int i = (l), i##end = (int)(r); i <= i##end; ++i)
    #define Fordown(i, r, l) for(register int i = (r), i##end = (int)(l); i >= i##end; --i)
    #define Set(a, v) memset(a, v, sizeof(a))
    #define Cpy(a, b) memcpy(a, b, sizeof(a))
    #define debug(x) cout << #x << ": " << (x) << endl
    #define DEBUG(...) fprintf(stderr, __VA_ARGS__)
    #define pb push_back
    
    using namespace std;
    
    typedef unsigned long long ull;
    
    template<typename T> inline bool chkmin(T &a, T b) {return b < a ? a = b, 1 : 0;}
    template<typename T> inline bool chkmax(T &a, T b) {return b > a ? a = b, 1 : 0;}
    
    namespace pb_ds
    {   
    	namespace io
    	{
    		const int MaxBuff = 1 << 22;
    		const int Output = 1 << 24;
    		char B[MaxBuff], *S = B, *T = B;
    #define getc() ((S == T) && (T = (S = B) + fread(B, 1, MaxBuff, stdin), S == T) ? 0 : *S++)
    		char Out[Output], *iter = Out;
    		inline void flush()
    		{
    			fwrite(Out, 1, iter - Out, stdout);
    			iter = Out;
    		}
    	}
    
    	template<class Type> inline Type read()
    	{
    		using namespace io;
    		register char ch; register Type ans = 0; register bool neg = 0;
    		while(ch = getc(), (ch < '0' || ch > '9') && ch != '-')     ;
    		ch == '-' ? neg = 1 : ans = ch - '0';
    		while(ch = getc(), '0' <= ch && ch <= '9') ans = ans * 10 + ch - '0';
    		return neg ? -ans : ans;
    	}
    
    	template<class Type> inline void Print(register Type x, register char ch = '
    ')
    	{
    		using namespace io;
    		if(!x) *iter++ = '0';
    		else
    		{
    			if(x < 0) *iter++ = '-', x = -x;
    			static int s[100]; register int t = 0;
    			while(x) s[++t] = x % 10, x /= 10;
    			while(t) *iter++ = '0' + s[t--];
    		}
    		*iter++ = ch;
    	}
    
    }
    
    using namespace pb_ds;
    
    void File() {
    #ifdef zjp_shadow
    	freopen ("P3613.in", "r", stdin);
    	freopen ("P3613.out", "w", stdout);
    #endif
    }
    
    const int N = 1e5 + 1e3;
    
    #define ls(o) ch[o][0]
    #define rs(o) ch[o][1]
    
    struct Data {
    	ull r0, r1;
    };
    
    inline Data operator + (const Data &lhs, const Data &rhs) {
    	return (Data) {
    		(~lhs.r0 & rhs.r0) | (lhs.r0 & rhs.r1),
    		(~lhs.r1 & rhs.r0) | (rhs.r1 & lhs.r1)
    	};
    }
    
    template<int Maxn>
    struct Link_Cut_Tree {
    
    	int ch[Maxn][2], fa[Maxn];
    
    	Data fo[Maxn], fr[Maxn], val[Maxn];
    
    	inline bool is_root(int o) {
    		return ls(fa[o]) != o && rs(fa[o]) != o;
    	}
    
    	inline bool get(int o) {
    		return rs(fa[o]) == o;
    	}
    
    	inline void push_up(int o) {
    		fo[o] = fr[o] = val[o];
    		if (ls(o)) fo[o] = fo[ls(o)] + fo[o], fr[o] = fr[o] + fr[ls(o)];
    		if (rs(o)) fo[o] = fo[o] + fo[rs(o)], fr[o] = fr[rs(o)] + fr[o];
    	}
    
    	inline void rotate(int v) {
    		int u = fa[v], t = fa[u], d = get(v);
    		fa[ch[u][d] = ch[v][d ^ 1]] = u;
    		fa[v] = t; if (!is_root(u)) ch[t][rs(t) == u] = v;
    		fa[ch[v][d ^ 1] = u] = v;
    		push_up(v); push_up(u);
    	}
    
    	bool rev[Maxn];
    
    	inline void Get_Rev(int o) {
    		rev[o] ^= 1; 
    		swap(ls(o), rs(o));
    		swap(fo[o], fr[o]);
    	}
    
    	inline void push_down(int o) {
    		if (rev[o])
    			Get_Rev(ls(o)), Get_Rev(rs(o)), rev[o] = false;
    	}
    
    	void Push_All(int o) {
    		if (!is_root(o)) Push_All(fa[o]); push_down(o);
    	}
    
    	inline void Splay(int o) {
    		Push_All(o);
    		for (; !is_root(o); rotate(o))
    			if (!is_root(fa[o])) rotate(get(o) != get(fa[o]) ? o : fa[o]);
    		push_up(o);
    	}
    
    	inline void Access(int o) {
    		for (int t = 0; o; o = fa[t = o])
    			Splay(o), rs(o) = t, push_up(o);
    	}
    
    	inline void Make_Root(int o) {
    		Access(o); Splay(o); Get_Rev(o);
    	}
    
    	inline void Split(int u, int v) {
    		Make_Root(u); Access(v); Splay(v);
    	}
    
    };
    
    Link_Cut_Tree<N> T;
    
    vector<int> G[N];
    void Build(int u = 1, int fa = 0) {
    	T.fa[u] = fa; for (int v : G[u]) if (v != fa) Build(v, u);
    }
    
    int main () {
    
    	File();
    
    	int n = read<int>(), m = read<int>(), k = read<int>();
    
    	For (i, 1, n) {
    		int x = i, y = read<int>(); ull z = read<ull>();
    		if (y == 1) T.val[x].r0 = 0ull, T.val[x].r1 = z;
    		if (y == 2) T.val[x].r0 = z, T.val[x].r1 = ~0ull;
    		if (y == 3) T.val[x].r0 = z, T.val[x].r1 = ~z;
    		T.push_up(x);
    	}
    
    	For (i, 1, n - 1) { int u = read<int>(), v = read<int>(); G[u].pb(v); G[v].pb(u); } Build();
    
    	For (i, 1, m) {
    		int opt = read<int>(), x = read<int>(), y = read<int>(); ull z = read<ull>();
    		if (opt == 1) {
    			T.Split(x, y);
    			ull val0 = T.fo[y].r0, val1 = T.fo[y].r1, res = 0, cur = 0;
    			for (ull i = 1ull << (k - 1); i; i >>= 1) {
    				if ((val0 & i) < (val1 & i) && cur + i <= z)
    					cur += i, res += val1 & i;
    				else res += val0 & i;
    			}
    			Print(res);
    		} else {
    			T.Access(x); T.Splay(x);
    			if (y == 1) T.val[x].r0 = 0ull, T.val[x].r1 = z;
    			if (y == 2) T.val[x].r0 = z, T.val[x].r1 = ~0ull;
    			if (y == 3) T.val[x].r0 = z, T.val[x].r1 = ~z;
    			T.push_up(x);
    		}
    	}
    	io :: flush();
    
    	return 0;
    
    }
    
  • 相关阅读:
    Qt之添加QLabel的点击事件
    Qt之布局管理--基本布局
    Qt之界面实现技巧
    Qt之键盘讲解
    Qt之多窗口切换
    Qt之自定义信号和槽函数
    Qt之重写QLabel类
    mysql学习(四)-字段类型
    mysql学习(三)
    mysql 复习与学习(二)数据库及表结构的创建删除
  • 原文地址:https://www.cnblogs.com/zjp-shadow/p/9733086.html
Copyright © 2020-2023  润新知