[洛谷P3613]睡觉困难综合征

题目大意:[NOI2014]起床困难综合症加强版,出到树上,$m(m\leqslant10^5)$组询问,带修改,数的范围$<2^{64})$

题解:先想到树剖,转化为序列问题,线段树维护区间从左到右和从右到左$01$变化值,然后发现如果对每一位考虑,复杂度为$O(64n\log_2^2n)$,$0.5s$时限并过不去。考虑去掉$k$,可以使用位运算来$O(1)$合并区间。

注意树剖询问的时候要按顺序修改,不可以反过来。

卡点:



C++ Code:

#include <algorithm>
#include <cstdio>
#include <cctype>
namespace __IO {
	int x, ch;
	inline int read() {
		while (isspace(ch = getchar())) ;
		for (x = ch & 15; isdigit(ch = getchar()); ) x = x * 10 + (ch & 15);
		return x;
	}
	unsigned long long X;
	inline unsigned long long readllu() {
		while (isspace(ch = getchar())) ;
		for (X = ch & 15; isdigit(ch = getchar()); ) X = X * 10 + (ch & 15);
		return X;
	}
}
using __IO::read;
using __IO::readllu;

const int maxn = 100010;
const unsigned long long inf = ~0;

int Opt[maxn], __Opt[maxn];
unsigned long long Num[maxn], __Num[maxn];
int n, m, __p;
inline void calc(unsigned long long &x, int y, unsigned long long z) {
	switch (y) {
		case 1: x &= z; break;
		case 2: x |= z; break;
		case 3: x ^= z;
	}
}
struct node {
	unsigned long long __0, __1;
	inline friend node operator + (const node &lhs, const node &rhs) {
		return (node) {
			(lhs.__0 & rhs.__1) | (~lhs.__0 & rhs.__0),
			(lhs.__1 & rhs.__1) | (~lhs.__1 & rhs.__0)
		};
	}
} ;
namespace SgT {
	const int N = maxn << 2;
	node lr[N], rl[N];

	void build(const int rt, const int l, const int r) {
		if (l == r) {
			calc(lr[rt].__0 = 0, Opt[l], Num[l]);
			calc(lr[rt].__1 = inf, Opt[l], Num[l]);
			calc(rl[rt].__0 = 0, Opt[l], Num[l]);
			calc(rl[rt].__1 = inf, Opt[l], Num[l]);
			return ;
		}
		const int mid = l + r >> 1, lc = rt << 1, rc = rt << 1 | 1;
		build(lc, l, mid), build(rc, mid + 1, r);
		lr[rt] = lr[lc] + lr[rc];
		rl[rt] = rl[rc] + rl[lc];
	}

	int pos;
	void __modify(const int rt, const int l, const int r) {
		if (l == r) {
			calc(lr[rt].__0 = 0, Opt[l], Num[l]);
			calc(lr[rt].__1 = inf, Opt[l], Num[l]);
			calc(rl[rt].__0 = 0, Opt[l], Num[l]);
			calc(rl[rt].__1 = inf, Opt[l], Num[l]);
			return ;
		}
		const int mid = l + r >> 1, lc = rt << 1, rc = rt << 1 | 1;
		if (pos <= mid) __modify(lc, l, mid);
		else __modify(rc, mid + 1, r);
		lr[rt] = lr[lc] + lr[rc];
		rl[rt] = rl[rc] + rl[lc];
	}
	void modify(int __pos, int y, unsigned long long z) {
		pos = __pos;
		Opt[pos] = y;
		Num[pos] = z;
		__modify(1, 1, n);
	}

	int L, R;
	node res;
	void querylr(const int rt, const int l, const int r) {
		if (L <= l && R >= r) {
			res = res + lr[rt];
			return ;
		}
		const int mid = l + r >> 1;
		if (L <= mid) querylr(rt << 1, l, mid);
		if (R > mid) querylr(rt << 1 | 1, mid + 1, r);
	}
	void queryrl(const int rt, const int l, const int r) {
		if (L <= l && R >= r) {
			res = res + rl[rt];
			return ;
		}
		const int mid = l + r >> 1;
		if (R > mid) queryrl(rt << 1 | 1, mid + 1, r);
		if (L <= mid) queryrl(rt << 1, l, mid);
	}
	node query(int __L, int __R) {
		res.__0 = 0, res.__1 = inf;
		if (__L <= __R) {
			L = __L, R = __R;
			querylr(1, 1, n);
		} else {
			L = __R, R = __L;
			queryrl(1, 1, n);
		}
		return res;
	}
}

int head[maxn], cnt;
struct Edge {
	int to, nxt;
} e[maxn << 1];
inline void addedge(int a, int b) {
	e[++cnt] = (Edge) { b, head[a] }; head[a] = cnt;
	e[++cnt] = (Edge) { a, head[b] }; head[b] = cnt;
}

int fa[maxn], dep[maxn], sz[maxn];
int dfn[maxn], idx, top[maxn], son[maxn];
void dfs1(int u) {
	sz[u] = 1;
	for (int i = head[u]; i; i = e[i].nxt) {
		int v = e[i].to;
		if (v != fa[u]) {
			fa[v] = u;
			dep[v] = dep[u] + 1;
			dfs1(v);
			if (!son[u] || sz[v] > sz[son[u]]) son[u] = v;
			sz[u] += sz[v];
		}
	}
}
void dfs2(int u) {
	dfn[u] = ++idx;
	int v = son[u];
	if (v) top[v] = top[u], dfs2(v);
	for (int i = head[u]; i; i = e[i].nxt) {
		int v = e[i].to;
		if (v != fa[u] && v != son[u]) {
			top[v] = v;
			dfs2(v);
		}
	}
}

unsigned long long query(int x, int y, unsigned long long z) {
	static node res, S[maxn];
	int tot = 0;
	res.__0 = 0, res.__1 = inf;
	while (top[x] != top[y]) {
		if (dep[top[x]] > dep[top[y]]) {
			res = res + SgT::query(dfn[x], dfn[top[x]]);
			x = fa[top[x]];
		} else {
			S[++tot] = SgT::query(dfn[top[y]], dfn[y]);
			y = fa[top[y]];
		}
	}
	res = res + SgT::query(dfn[x], dfn[y]);
	while (tot) res = res + S[tot--];
	unsigned long long ans = 0, ret = 0;
	for (int i = 63; ~i; --i) {
		if (res.__0 >> i & 1) ret |= 1ull << i;
		else if (res.__1 >> i & 1) {
			if ((ans | 1ull << i) <= z) {
				ans |= 1ull << i;
				ret |= 1ull << i;
			}
		}
	}
	return ret;
}

int main() {
	n = read(), m = read(), __p = read();
	for (int i = 1; i <= n; ++i) {
		__Opt[i] = read(), __Num[i] = readllu();
	}
	for (int i = 1, a, b; i < n; ++i) {
		a = read(), b = read();
		addedge(a, b);
	}
	dfs1(1), dfs2(top[1] = 1);
	for (int i = 1; i <= n; ++i) Opt[dfn[i]] = __Opt[i], Num[dfn[i]] = __Num[i];
	SgT::build(1, 1, n);

	while (m --> 0) {
		static int op, x, y;
		static unsigned long long z;
		op = read(), x = read(), y = read(), z = readllu();
		if (op == 1) {
			printf("%llu\n", query(x, y, z));
		} else {
			SgT::modify(dfn[x], y, z);
		}
	}
	return 0;
}

猜你喜欢

转载自www.cnblogs.com/Memory-of-winter/p/10286499.html