#H1034. [Ynoi2017] 由乃的 OJ

题目描述

由乃正在做她的 OJ 。现在她在处理 OJ 上的用户排名问题。 OJ 上注册了 �n 个用户,编号为 1−�1−n,一开始他们按照编号排名。由乃会按照心情对这些用户做以下四种操作,修改用户的排名和编号:然而由乃心情非常不好,因为 Deus 天天问她题。。。因为 Deus 天天问由乃 OI 题,所以由乃去学习了一下 OI,由于由乃智商挺高,所以 OI 学的特别熟练她在 RBOI2016 中以第一名的成绩进入省队,参加了 NOI2016 获得了金牌保送。

Deus:这个题怎么做呀?
yuno:这个不是 NOI2014 的水题吗。。。
Deus:那如果出到树上,多组链询问,带修改呢?
yuno:诶。。。???
Deus:这题叫做睡觉困难综合征哟~

虽然由乃 OI 很好,但是她基本上不会 DS,线段树都只会口胡,比如她 NOI2016 的分数就是 100+100+100+0+100+100100+100+100+0+100+100。。。NOIP2017的分数是 100+0+100+100+0+100100+0+100+100+0+100 所以她还是只能找你帮她做了。。。

给你一个有 �n 个点的树,每个点的包括一个位运算 opt⁡opt 和一个权值 �x,位运算有 &,|,^ 三种,分别用 1,2,31,2,3 表示。

每次询问包含三个数 �,�,�x,y,z,初始选定一个数 �v。然后 �v 依次经过从 �x 到 �y 的所有节点,每经过一个点 �i,�v 就变成 �opt⁡��voptxi​。

所以他想问你,最后到 �y 时,希望得到的值尽可能大,求最大值?给定的初始值 �v 必须是在 [0,�][0,z] 之间。

每次修改包含三个数 �,�,�x,y,z,意思是把 �x 点的操作修改为 �y,数值改为 �z。

输入格式

第一行三个数 �,�,�n,m,k。�k 的意义是每个点上的数,以及询问中的数值 �<2�z<2k。
之后 �n 行每行两个数 �,�x,y 表示该点的位运算编号以及数值。
之后 �−1n−1 行,每行两个数 �,�x,y 表示 �x 和 �y 之间有边相连。
之后 �m 行,每行四个数,�,�,�,�Q,x,y,z 表示这次操作为 �Q (11 询问,22 修改),�,�,�x,y,z 意义如题所述。

输出格式

对于每个操作 11,输出到最后可以造成的最大刺激度 �v。

输入数据 1

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

输出数据 1

7
1
5

输入数据 2

2 2 2
2 2
2 2
1 2
2 2 2 2
1 2 2 2

输出数据 2

3

数据范围与约定

Idea:f321dd,Solution:f321dd&nzhtl1477,Code:nzhtl1477,Data:nzhtl1477

对于 30%30% 的数据,�,�≤1n,m≤1。

对于另外 20%20% 的数据,�≤5k≤5。

对于另外 20%20% 的数据,位运算只会出现一种。

对于 $100% 的数据,0≤�,�≤1050≤n,m≤105,0≤�≤640≤k≤64。

这道题是我有史以来做过的最难的题,代码最多的题


代码在这里:

#include<bits/stdc++.h>
using namespace std;

#define fec(i, x, y) (int i = head[x], y = g[i].to; i; i = g[i].ne, y = g[i].to)
#define dbg(...) fprintf(stderr, __VA_ARGS__)
#define File(x) freopen(#x".in", "r", stdin), freopen(#x".out", "w", stdout)
#define fi first
#define se second
#define pb push_back
 
template<typename A, typename B> inline char smax(A &a, const B &b) {return a < b ? a = b , 1 : 0;}
template<typename A, typename B> inline char smin(A &a, const B &b) {return b < a ? a = b , 1 : 0;}
 
typedef long long ll; typedef unsigned long long ull; typedef std::pair<int, int> pii;
 
template<typename I>
inline void read(I &x) {
	int f = 0, c;
	while (!isdigit(c = getchar())) c == '-' ? f = 1 : 0;
	x = c & 15;
	while (isdigit(c = getchar())) x = (x << 1) + (x << 3) + (c & 15);
	f ? x = -x : 0;
}
 
#define lc o << 1
#define rc o << 1 | 1
 
const int N = 100000 + 7;
 
int n, m, k, dfc;
ull S;
int opt[N];
ull v[N];
int dep[N], f[N], siz[N], son[N], dfn[N], pre[N], top[N];
 
struct Edge { int to, ne; } g[N << 1]; int head[N], tot;
inline void addedge(int x, int y) { g[++tot].to = y, g[tot].ne = head[x], head[x] = tot; }
inline void adde(int x, int y) { addedge(x, y), addedge(y, x); }
 
struct Node {
	ull s[2], r[2];
	inline Node() : s{0, S}, r{0, S} {}
	inline Node(const int &i) {
		int opt = ::opt[i];
		ull v = ::v[i];
		if (opt == 1) s[0] = 0, s[1] = v;
		else if (opt == 2) s[0] = v, s[1] = S;
		else s[0] = v, s[1] = (~v) & S;
		r[0] = s[0], r[1] = s[1];
	}
	inline Node(const ull &x, const ull &y) : s{x, y}, r{x, y} {}
} t[N << 2];
inline Node operator + (const Node &a, const Node &b) {
	Node ans;
	ans.s[0] = (a.s[0] & b.s[1]) | ((~a.s[0]) & b.s[0]);
	ans.s[1] = (a.s[1] & b.s[1]) | ((~a.s[1]) & b.s[0]);
	ans.r[0] = (b.r[0] & a.r[1]) | ((~b.r[0]) & a.r[0]);
	ans.r[1] = (b.r[1] & a.r[1]) | ((~b.r[1]) & a.r[0]);
	// dbg("******* %llu, %llu;    %llu, %llu;     %llu, %llu\n", a.s[0], a.s[1], b.s[0], b.s[1], ans.s[0], ans.s[1]);
	return ans;
}
inline Node operator - (const Node &a) {
	Node ans;
	ans.s[0] = a.r[0], ans.s[1] = a.r[1];
	ans.r[0] = a.s[0], ans.r[1] = a.s[1];
	return ans;
}
 
inline void build(int o, int L, int R) {
	if (L == R) return t[o] = Node(pre[L]), (void)0;
	int M = (L + R) >> 1;
	build(lc, L, M), build(rc, M + 1, R);
	t[o] = t[lc] + t[rc];
}
inline void qadd(int o, int L, int R, int x) {
	if (L == R) return t[o] = Node(pre[L]), (void)0;
	int M = (L + R) >> 1;
	if (x <= M) qadd(lc, L, M, x);
	else qadd(rc, M + 1, R, x);
	t[o] = t[lc] + t[rc];
}
inline Node qsum(int o, int L, int R, int l, int r) {
	if (l <= L && R <= r) return t[o];
	int M = (L + R) >> 1;
	if (r <= M) return qsum(lc, L, M, l, r);
	if (l > M) return qsum(rc, M + 1, R, l, r);
	return qsum(lc, L, M, l, r) + qsum(rc, M + 1, R, l, r);
}
 
inline Node qry(int x, int y) {
	Node ans1, ans2;
	while (top[x] != top[y]) {
		if (dep[top[x]] > dep[top[y]]) {
			ans1 = qsum(1, 1, n, dfn[top[x]], dfn[x]) + ans1;
			x = f[top[x]];
		} else {
			ans2 = qsum(1, 1, n, dfn[top[y]], dfn[y]) + ans2;
			y = f[top[y]];
		}
	}
	// dbg("x = %d, y = %d, dfn: %d %d\n", x, y, dfn[x], dfn[y]);
	if (dep[x] < dep[y]) ans2 = qsum(1, 1, n, dfn[x], dfn[y]) + ans2;
	else ans1 = qsum(1, 1, n, dfn[y], dfn[x]) + ans1;
	ans1 = (-ans1) + ans2;
	return ans1;
}
inline ull solve(int x, int y, ull z) {
	Node a = qry(x, y);
	ull ans = 0, lim = 1;
	for (int i = k - 1; ~i; --i) {
		if ((!lim || ((z >> i) & 1)) && !((a.s[0] >> i) & 1) && ((a.s[1] >> i) & 1)) ans |= 1ull << i;
		else ans |= (1ull << i) & a.s[0], lim = lim && !((z >> i) & 1);
	}
	return ans;
}
 
inline void dfs1(int x, int fa = 0) {
	dep[x] = dep[fa] + 1, f[x] = fa, siz[x] = 1;
	for fec(i, x, y) if (y != fa) dfs1(y, x), siz[x] += siz[y], siz[y] > siz[son[x]] && (son[x] = y);
}
inline void dfs2(int x, int pa) {
	top[x] = pa, dfn[x] = ++dfc, pre[dfc] = x;
	if (!son[x]) return; dfs2(son[x], pa);
	for fec(i, x, y) if (y != f[x] && y != son[x]) dfs2(y, y);
}
 
inline void work() {
	dfs1(1), dfs2(1, 1), build(1, 1, n);
	while (m--) {
		int opt, x, y;
		ull z;
		read(opt), read(x), read(y), read(z);
		if (opt == 2) ::opt[x] = y, v[x] = z, qadd(1, 1, n, dfn[x]);
		else printf("%llu\n", solve(x, y, z));
	}
}
 
inline void init() {
	read(n), read(m), read(k);
	if (k < 64) S = (1ull << k) - 1;
	else S = -1;
	for (int i = 1; i <= n; ++i) read(opt[i]), read(v[i]);
	int x, y;
	for (int i = 1; i < n; ++i) read(x), read(y), adde(x, y);
}
 
int main() {
#ifdef hzhkk
	freopen("hkk.in", "r", stdin);
#endif
	init();
	work();
	fclose(stdin), fclose(stdout);
	return 0;
}

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值