重庆八中集训 day1

T1

题意

给你一个长度为 \(n\) 的序列 \(a\)\(Q\) 次查询,每次查询 \([l,r]\) 区间内把所有出现次数大于 \(w\) 的数字视为 \(\infty\) 之后的第 \(k\) 小值。

满足 \(0\le a_i < N, 1\le N, Q\le 10 ^ 5\)

题解

忽视次数为 \(w\) 的数字,怎么办?思考一下,发现可以搞一个暴力莫队+线段树,时间复杂度为 \(O(N\log N \sqrt N)\)。发现只有 \(N\) 次询问但是居然有 \(N\sqrt N\) 次插入和删除,我们如果使用线段树很亏,考虑平衡一下复杂度,使用插入 \(O(1)\),查询 \(O(\sqrt N)\) 的分块来维护即可。具体而言,一个区间k大是有方法 \(O(1)-O(\sqrt N)\) 的,具体做法是维护值域分块,还有一个桶。
值域分块就是把值域做分块,维护每一块有多少个数。那么可以用 \(\sqrt N\) 的时间确定答案在哪一块,然后暴力扫这个块,通过桶定位答案。
现在它要求我们在线,思考能不能去掉莫队。那么问题就是如何在线得到一段区间的值域分块?
怎么办?有一个解决方法是把序列再次分块,预处理第 \(i\) 块到第 \(j\) 块的值域分块,然后复杂度都是 \(O(N\sqrt N)\) 的。桶怎么做?我们只要看看能不能快速得到一个数在区间内的出现次数即可。

怎么办?考虑维护 \(num[i][j]\) 表示数字 \(i\)\(1\sim j\) 块内出现了多少次,那么整块直接做差,然后边角可以暴力加入桶就好了。

// Siriqwq
#include <bits/stdc++.h>
using std::cin;
using std::cout;
using std::vector;
using std::copy;
using std::reverse;
using std::sort;
using std::get;
using std::unique;
using std::swap;
using std::array;
using std::cerr;
using std::function;
using std::map;
using std::set;
using std::pair;
using std::mt19937;
using std::make_pair;
using std::tuple;
using std::make_tuple;
using std::uniform_int_distribution;
using ll = long long;
namespace qwq {
	mt19937 eng;
	void init(int Seed) {return eng.seed(Seed);}
	int rnd(int l = 1, int r = 1000000000) {return uniform_int_distribution<int> (l, r)(eng);}
}
template<typename T>
inline void chkmin(T &x, T y) {if (x > y) x = y;}
template<typename T>
inline void chkmax(T &x, T y) {if (x < y) x = y;}
template<typename T>
inline T min(const T &x, const T &y) {return x < y ? x : y;}
template<typename T>
inline T max(const T &x, const T &y) {return x > y ? x : y;}
char buf[100000], *bufs, *buft;
#define gc() ((bufs == buft && (buft = (bufs = buf) + fread(buf, 1, 100000, stdin))), bufs == buft ? -1 : *bufs++)
template<typename T>
inline void read(T &x) {
	x = 0;
	bool f = 0;
	char ch = gc();
	while (!isdigit(ch)) f = ch == '-', ch = gc();
	while (isdigit(ch)) x = x * 10 + ch - '0', ch = gc();
	if (f) x = -x;
}
inline void reads(char *s) {
	char ch = gc();
	while (isspace(ch)) ch = gc();
	while (!isspace(ch) && ch != EOF) *(s++) = ch, ch = gc();
	*s = 0;
	return;
}
template<typename T, typename ...Arg>
inline void read(T &x, Arg &... y) {
	read(x);
	read(y...);
}
#define O(x) cerr << #x << " : " << x << '\n'
const double Pi = acos(-1);
const int MOD = 998244353, inv2 = (MOD + 1) / 2, I32_INF = 0x3f3f3f3f;
const long long I64_INF = 0x3f3f3f3f3f3f3f3f;
auto Ksm = [] (int x, int y) -> int {
	if (y < 0) {
		y %= MOD - 1;
		y += MOD - 1;
	}
	int ret = 1;
	for (; y; y /= 2, x = (long long) x * x % MOD) if (y & 1) ret = (long long) ret * x % MOD;
	return ret;
};
auto Mod = [] (int x) -> int {
	if (x >= MOD) return x - MOD;
	else if (x < 0) return x + MOD;
	else return x;
};
template<const int N_num, const int M_num>
struct Graph {
	int H[N_num];
	struct Edge {int to, lac;} e[M_num];
	inline void add_edge(int x, int y) {e[*H] = {y, H[x]};H[x] = (*H)++;}
	inline void init() {memset(H, -1, sizeof H);*H = 0;}
};
#define go(x, y) for (int i = x.H[y], v; (v = x.e[i].to) && ~i; i = x.e[i].lac)
inline int ls(int k) {return k << 1;}
inline int rs(int k) {return k << 1 | 1;}
using ull = unsigned long long;
const int MAXN = 1e5 + 10, MAXB = 505;
int buc[MAXN], F[505][505][505], num[MAXN][505];
// buc[i] 表示桶, F[i][j][k] 表示第 i 块到第 j 块的值域分块中第 k 块的总和
// num[i][j] 表示数字 i 在前 j 块的出现次数
int N, w, type, Q, blk_sz, bel[MAXN], L[MAXB], R[MAXB], blk_num, A[MAXN];
int tmp[MAXB];
inline int NUM(int l, int r, int p) {return num[p][r] - num[p][l - 1];}
int qry(int ql, int qr, int K) {
	memset(tmp, 0, sizeof tmp);
	int ans = N + 1;
	if (bel[ql] == bel[qr]) {
		for (int i = ql; i <= qr; ++i) {
			if (++buc[A[i]] == w + 1) {
				tmp[bel[A[i]]] -= w;
			} else if (buc[A[i]] <= w) ++tmp[bel[A[i]]];
		}
		int p = 0;
		for (int i = 1; i <= blk_num && K > 0; ++i) {
			if (K <= tmp[i]) p = i;
			K -= tmp[i];
		}
		K += tmp[p];
		if (p) for (int i = L[p]; i <= R[p] && K > 0; ++i) if (buc[i] <= w) {
			if (K <= buc[i]) ans = i;
			K -= buc[i];
		}
		for (int i = ql; i <= qr; ++i) --buc[A[i]];
	} else {
		int bl = bel[ql], br = bel[qr];
		memcpy(tmp, F[bl + 1][br - 1], sizeof tmp);
		for (int i = ql; i <= R[bl]; ++i) {
			if (++buc[A[i]] + NUM(bl + 1, br - 1, A[i]) == w + 1) tmp[bel[A[i]]] -= w;
			else if (buc[A[i]] + NUM(bl + 1, br - 1, A[i]) <= w) ++tmp[bel[A[i]]];
		}
		for (int i = L[br]; i <= qr; ++i) {
			if (++buc[A[i]] + NUM(bl + 1, br - 1, A[i]) == w + 1) tmp[bel[A[i]]] -= w;
			else if (buc[A[i]] + NUM(bl + 1, br - 1, A[i]) <= w) ++tmp[bel[A[i]]];
		}
		int p = 0;
		for (int i = 1; i <= blk_num && K > 0; ++i) {
			if (K <= tmp[i]) p = i;
			K -= tmp[i];
		}
		K += tmp[p];
		if (p) for (int i = L[p]; i <= R[p] && K > 0; ++i) if (buc[i] + NUM(bl + 1, br - 1, i) <= w) {
			if (K <= buc[i] + NUM(bl + 1, br - 1, i)) ans = i;
			K -= buc[i] + NUM(bl + 1, br - 1, i);
		}
		for (int i = ql; i <= R[bl]; ++i) --buc[A[i]];
		for (int i = L[br]; i <= qr; ++i) --buc[A[i]];
	}
	return ans;
}
int main() {
	freopen("kth.in", "r", stdin);
	freopen("kth.out", "w", stdout);
	// std::ios::sync_with_stdio(0);
	// cout << std::fixed << std::setprecision(8);
	// cin.tie(0);
	// cout.tie(0);
	qwq::init(20050112);
	read(N, w, Q, type);
	blk_sz = 200;
	for (int i = 1; i <= N; ++i) {
		R[bel[i] = (i - 1) / blk_sz + 1] = i;
		if (!L[bel[i]]) L[bel[i]] = i;
	}
	blk_num = bel[N];
	for (int i = 1; i <= N; ++i) read(A[i]), ++A[i];
	for (int i = 1; i <= blk_num; ++i) {
		for (int j = i; j <= blk_num; ++j) {
			memcpy(F[i][j], F[i][j - 1], sizeof F[i][j]);
			for (int k = L[j]; k <= R[j]; ++k) {
				if (++buc[A[k]] == w + 1) F[i][j][bel[A[k]]] -= w;
				else if (buc[A[k]] <= w) ++F[i][j][bel[A[k]]];
			}
			if (i == 1) for (int k = 1; k <= N; ++k) num[k][j] = buc[k];
		}
		memset(buc, 0, sizeof buc);
	}
	for (int lstans = 0, l, r, k; Q--; ) {
		read(l, r, k);
		l ^= lstans * type;
		r ^= lstans * type;
		k ^= lstans * type;
		lstans = qry(l, r, k);
		printf("%d\n", --lstans);
	}
	// cout << (-3 / 2);
	cerr << ((double) clock() / CLOCKS_PER_SEC) << '\n';
	return (0-0);
}

T2

题意

众所周知 $\mu(i) = \prod_{i}(-1) ^ {a_i}[a_i \le 1] $,记 \(f_d(x) =\prod_{i}(-1) ^ {a_i}[a_i \le d]\)

\(\sum_{x = 1} ^ {N}\sum_{y = 1} ^ N\sum_{d = 1} ^ K f_d((x, y))\)

题解

\[\begin{aligned} LHS&=\sum_{x = 1} ^ {N}\sum_{d = 1} ^ K f_d(x) \sum_{i = 1} ^ {\left\lfloor \frac{N}{x} \right\rfloor} \sum_{j= 1} ^{\left\lfloor\frac{N}{x} \right\rfloor}\epsilon((i, j)) \\ &=\sum_{x = 1} ^ {N}\sum_{d = 1} ^ K f_d(x)\left( 2 \sum_{i = 1} ^ {\left\lfloor \frac{N}{x} \right\rfloor}\varphi (i) - 1\right) \end {aligned} \]

我们 \(\varphi (x)\) 的前缀和可以使用杜教筛解决,那么现在的问题就是对于某个 \(d\),怎么求 \(\sum_{i = 1} ^ x f_d(i)\)

\(x\) 分解的结果是 \(\prod_{i} p_i ^ {a_i}\),定义 \(\lambda(x) = f_{\infty}(x)\)\(\lambda\) 是完全积性函数。

我们考虑 \(i ^ {d + 1} | x\) 的话,那么 \(f_{d}(x)= 0\),按照 \(\sum_{i|x} \mu(i) = [x = 1]\),记 \(F_d (x) = \sum_{i = 1} ^ xf_d(i)\)可以得到

\[\begin{aligned} F_d(x) &= \sum_{i = 1} ^ x\mu(i) \sum_{j = 1} ^ {\left\lfloor\frac{N}{i ^ {d + 1}}\right\rfloor} \lambda(i ^ {d + 1} j)\\ &= \sum_{i = 1 } ^ x \mu(i) \lambda ^ {d + 1}(i)\sum_{j = 1} ^ {\left\lfloor\frac{N}{i ^ {d + 1}}\right\rfloor} \lambda (j) \end{aligned} \]

\(\Lambda (x) = \sum_{i = 1} ^ x \lambda(i)\),应该有 \(F_d(x) = \sum_{i = 1} ^ x \lambda ^ {d + 1}(i) \Lambda(\left\lfloor\frac{N}{i ^ {d + 1}} \right\rfloor)\),更进一步的,应该是 \(F_d(x) = \sum_{i = 1} ^ {\left \lfloor x ^ \frac{1}{d + 1} \right\rfloor} \lambda ^ {d + 1}(i) \mu(i) \Lambda (\left \lfloor\frac{N}{i ^ {d + 1}}\right\rfloor)\)

\(x\) 较小的时候预处理,\(x\) 较大的时候直接计算,如果 \(\Lambda (x)\) 可以 \(O(1)\) 算,那就可以直接搞。

一个很牛的性质:\(\sum_{d | x} \lambda(x) = [x = y ^ 2]\),所以可以杜教筛,它可以卷上 \(I\) 然后就可以杜教筛。

所以我们就可以 \(O(N ^ \frac{2}{3})\) 的解决这个问题。

ps:如果不会杜教筛(我就不会),接着往下看,如果我要求

\[F(x) = \sum_{i = 1} ^ xf(i) \]

这歌东西的前缀和,那么我们考虑找一个积性函数 \(g\),如果能快速计算什么迪利克雷前缀和函数的东西。

\[\sum_{i = 1} ^ N (f*g)(i)= \sum_{i = 1} ^ Ng(i) F(\left\lfloor \frac{N}{i}\right\rfloor) \]

然后就可以做了,你考虑 \(\varphi * I = id\) 即可。

// Siriqwq
#include <bits/stdc++.h>
using std::cin;
using std::cout;
using std::vector;
using std::copy;
using std::reverse;
using std::sort;
using std::get;
using std::unique;
using std::swap;
using std::array;
using std::cerr;
using std::function;
using std::map;
using std::set;
using std::pair;
using std::mt19937;
using std::make_pair;
using std::tuple;
using std::make_tuple;
using std::uniform_int_distribution;
using ll = long long;
namespace qwq {
	mt19937 eng;
	void init(int Seed) {return eng.seed(Seed);}
	int rnd(int l = 1, int r = 1000000000) {return uniform_int_distribution<int> (l, r)(eng);}
}
template<typename T>
inline void chkmin(T &x, T y) {if (x > y) x = y;}
template<typename T>
inline void chkmax(T &x, T y) {if (x < y) x = y;}
template<typename T>
inline T min(const T &x, const T &y) {return x < y ? x : y;}
template<typename T>
inline T max(const T &x, const T &y) {return x > y ? x : y;}
char buf[100000], *bufs, *buft;
#define gc() ((bufs == buft && (buft = (bufs = buf) + fread(buf, 1, 100000, stdin))), bufs == buft ? -1 : *bufs++)
template<typename T>
inline void read(T &x) {
	x = 0;
	bool f = 0;
	char ch = gc();
	while (!isdigit(ch)) f = ch == '-', ch = gc();
	while (isdigit(ch)) x = x * 10 + ch - '0', ch = gc();
	if (f) x = -x;
}
inline void reads(char *s) {
	char ch = gc();
	while (isspace(ch)) ch = gc();
	while (!isspace(ch) && ch != EOF) *(s++) = ch, ch = gc();
	*s = 0;
	return;
}
template<typename T, typename ...Arg>
inline void read(T &x, Arg &... y) {
	read(x);
	read(y...);
}
#define O(x) cerr << #x << " : " << x << '\n'
const double Pi = acos(-1);
const int MOD = (1 << 30) - 1, I32_INF = 0x3f3f3f3f;
const long long I64_INF = 0x3f3f3f3f3f3f3f3f;
auto Ksm = [] (int x, int y) -> int {
	if (y < 0) {
		y %= MOD - 1;
		y += MOD - 1;
	}
	int ret = 1;
	for (; y; y /= 2, x = (long long) x * x % MOD) if (y & 1) ret = (long long) ret * x % MOD;
	return ret;
};
template<const int N_num, const int M_num>
struct Graph {
	int H[N_num];
	struct Edge {int to, lac;} e[M_num];
	inline void add_edge(int x, int y) {e[*H] = {y, H[x]};H[x] = (*H)++;}
	inline void init() {memset(H, -1, sizeof H);*H = 0;}
};
#define go(x, y) for (int i = x.H[y], v; (v = x.e[i].to) && ~i; i = x.e[i].lac)
inline int ls(int k) {return k << 1;}
inline int rs(int k) {return k << 1 | 1;}
using ull = unsigned long long;
const int MAXV = 5e6 + 10, LIM = 5e6, LIMM = 1e6;
using ui = unsigned int;
ll N;
ui K, vis[MAXV], pri[MAXV], phi[MAXV], sphi[MAXV], lambda[MAXV], slambda[MAXV], mu[MAXV], ans;
ui f[41][LIMM + 10];
void sieve() {
	for (int i = 1; i <= K; ++i) f[i][1] = 1;
	for (ui i = 2; i < MAXV; ++i) {
		if (!vis[i]) {
			pri[++*pri] = i, phi[i] = i - 1, lambda[i] = -1, mu[i] = -1;
			if (i <= LIMM) for (int j = 1; j <= K; ++j) f[j][i] = -1;
		}
		for (ui j = 1; j <= *pri && pri[j] * i < MAXV; ++j) {
			vis[i * pri[j]] = 1;
			lambda[i * pri[j]] = -lambda[i];
			if (i % pri[j])  {
				phi[i * pri[j]] = phi[i] * phi[pri[j]];
				mu[i * pri[j]] = -mu[i];
				int x = i * pri[j];
				if (x <= LIMM) for (int t = 1; t <= K; ++t) f[t][x] = -f[t][i];
			}
			else {
				phi[i * pri[j]] = phi[i] * pri[j];
				int tot = 1, tmp = i, x = pri[j] * i;
				if (x <= LIMM) {
					while (tmp % pri[j] == 0) ++tot, tmp /= pri[j];
					for (int t = tot; t <= K; ++t) f[t][x] = -f[t][i];
				}
				break;
			}
		}
	}
	sphi[1] = phi[1] = 1;
	mu[1] = 1;
	slambda[1] = lambda[1] = 1;
	for (int i = 2; i <= LIM; ++i) {
		sphi[i] = sphi[i - 1] + phi[i], slambda[i] = slambda[i - 1] + lambda[i];
		if (i <= LIMM) for (int j = 1; j <= K; ++j) f[j][i] += f[j][i - 1];
	}
}
namespace get_phi {
std::unordered_map<ll, ui> mp;
ui getphi(ll x) {
	if (x <= LIM) return sphi[x];
	if (mp.count(x)) return mp[x];
	ui y = (ui) x, ret = y * (y + 1) / 2;
	for (ll l = 2, r; l <= x; l = r + 1) {
		r = x / (x / l);
		ret -= (r - l + 1U) * getphi(x / l);
	}
	return mp[x] = ret;
}
}
namespace get_lambda {
std::unordered_map<ll, ui> mp;
ui getlambda(ll x) {
	if (x <= LIM) return slambda[x];
	if (mp.count(x)) return mp[x];
	ui y = (ui) x, ret = sqrt(x);
	for (ll l = 2, r; l <= x; l = r + 1) {
		r = x / (x / l);
		ret -= (r - l + 1U) * getlambda(x / l);
	}
	return mp[x] = ret;
}
}
ll sm[100010][41];
inline ui F(int d, ll x) {
	if (x <= LIMM) return f[d][x];
	ll lim = pow(x, 1.0 / (d + 1)) + 1;
	ui ret = 0;
	for (ll l = 1; l <= lim; ++l) if (mu[l]) {
		ui k = get_lambda::getlambda(x / sm[l][d]) * mu[l];
		if (lambda[l] == 1) ret += k;
		else if (d & 1) ret += k;
		else ret -= k;
	}
	return ret;
}
int main() {
	freopen("sum.in", "r", stdin);
	freopen("sum.out", "w", stdout);
	// std::ios::sync_with_stdio(0);
	// cout << std::fixed << std::setprecision(8);
	// cin.tie(0);
	// cout.tie(0);
	qwq::init(20050112);
	read(N, K);
	sieve();
	get_lambda::getlambda(N);
	get_phi::getphi(N);
	for (int i = 1; i < 100010; ++i) {
		sm[i][0] = i;
		for (int j = 1; j <= 40; ++j) sm[i][j] = sm[i][j - 1] * i;
	}
	ui ans = 0;
	for (ll l = 1, r; l <= N; l = r + 1) {
		r = N / (N / l);
		ui ret = 0;
		for (int i = 1; i <= K; ++i) ret += F(i, r) - F(i, l - 1);
		ret *= 2 * get_phi::getphi(N / l) - 1;
		ans += ret;
	}
	printf("%u\n", ans & MOD);
	// cout << (-3 / 2);
	cerr << ((double) clock() / CLOCKS_PER_SEC) << '\n';
	return (0-0);
}

T3

题意

一棵有 \(N\) 个点的树,然后定义一次消息传递为 \(u\to v\),经过的所有有向边 \((x,y)\),如果 \(x<y\) 那么 \(val_x\)\(val_y\) 加1,否则会让 \(val_x\)\(val_y\) 减去1。

然后经过若干次消息传递之后,现在有一个局面,问你原来的消息传递可能是什么。要求最少的消息,并且消息的字典序最小。

\(N\le 10^6\) 并且消息传递次数小于等于 \(N\)

题解

首先熊子豪跟我说,这题拿来就是能看出来先求出来每条边给两边的点有多少贡献。然后我们可以根据这条边两边的点的大小确定这个边的走向。

之后就是一个树形dp,具体而言我们已经知道了每条边怎么走了,然后要求一个点被当过多少次终点/起点。

一个性质是 \(u\to w, w\to v\) 的路径可以变为 \(u\to v\)

所以,可以直接树形dp来做,\(ct_i\) 就是一个点被当作起点/终点的次数。

然后我们还有一个性质,对于两条路径 \(a\to d, b\to c\),来说,他和 \(a\to c, b\to d\) 是等效的。

然后直接贪心做就可以。

// Siriqwq
#include <bits/stdc++.h>
using std::cin;
using std::cout;
using std::vector;
using std::copy;
using std::reverse;
using std::sort;
using std::get;
using std::unique;
using std::swap;
using std::array;
using std::cerr;
using std::function;
using std::map;
using std::set;
using std::pair;
using std::mt19937;
using std::make_pair;
using std::tuple;
using std::make_tuple;
using std::uniform_int_distribution;
using ll = long long;
namespace qwq {
	mt19937 eng;
	void init(int Seed) {return eng.seed(Seed);}
	int rnd(int l = 1, int r = 1000000000) {return uniform_int_distribution<int> (l, r)(eng);}
}
template<typename T>
inline void chkmin(T &x, T y) {if (x > y) x = y;}
template<typename T>
inline void chkmax(T &x, T y) {if (x < y) x = y;}
template<typename T>
inline T min(const T &x, const T &y) {return x < y ? x : y;}
template<typename T>
inline T max(const T &x, const T &y) {return x > y ? x : y;}
char buf[100000], *bufs, *buft;
#define gc() ((bufs == buft && (buft = (bufs = buf) + fread(buf, 1, 100000, stdin))), bufs == buft ? -1 : *bufs++)
template<typename T>
inline void read(T &x) {
	x = 0;
	bool f = 0;
	char ch = gc();
	while (!isdigit(ch)) f = ch == '-', ch = gc();
	while (isdigit(ch)) x = x * 10 + ch - '0', ch = gc();
	if (f) x = -x;
}
inline void reads(char *s) {
	char ch = gc();
	while (isspace(ch)) ch = gc();
	while (!isspace(ch) && ch != EOF) *(s++) = ch, ch = gc();
	*s = 0;
	return;
}
template<typename T, typename ...Arg>
inline void read(T &x, Arg &... y) {
	read(x);
	read(y...);
}
#define O(x) cerr << #x << " : " << x << '\n'
const double Pi = acos(-1);
const int MAXN = 1048576, MOD = 998244353, inv2 = (MOD + 1) / 2, I32_INF = 0x3f3f3f3f;
const long long I64_INF = 0x3f3f3f3f3f3f3f3f;
auto Ksm = [] (int x, int y) -> int {
	if (y < 0) {
		y %= MOD - 1;
		y += MOD - 1;
	}
	int ret = 1;
	for (; y; y /= 2, x = (long long) x * x % MOD) if (y & 1) ret = (long long) ret * x % MOD;
	return ret;
};
auto Mod = [] (int x) -> int {
	if (x >= MOD) return x - MOD;
	else if (x < 0) return x + MOD;
	else return x;
};
template<const int N_num, const int M_num>
struct Graph {
	int H[N_num];
	struct Edge {int to, lac;} e[M_num];
	inline void add_edge(int x, int y) {e[*H] = {y, H[x]};H[x] = (*H)++;}
	inline void init() {memset(H, -1, sizeof H);*H = 0;}
};
#define go(x, y) for (int i = x.H[y], v; (v = x.e[i].to) && ~i; i = x.e[i].lac)
inline int ls(int k) {return k << 1;}
inline int rs(int k) {return k << 1 | 1;}
using ull = unsigned long long;
int N, v[MAXN], dp[MAXN], ct[MAXN], fa[MAXN];
Graph<MAXN, MAXN * 2> tr;
void dfs(int u) {
	dp[u] = v[u];
	go(tr, u) if (v != fa[u]) {
		fa[v] = u;
		dfs(v);
		dp[u] -= dp[v];
	}
}
void dfs1(int u) {
	ct[u] = dp[u];
	go(tr, u) if (v != fa[u]) {
		dfs1(v);
		ct[u] -= dp[v];
	}
}
int main() {
	freopen("tree.in", "r", stdin);
	freopen("tree.out", "w", stdout);
	// std::ios::sync_with_stdio(0);
	// cout << std::fixed << std::setprecision(8);
	// cin.tie(0);
	// cout.tie(0);
	qwq::init(20050112);
	read(N);
	tr.init();
	for (int i = 1; i <= N; ++i) read(v[i]);
	for (int i = 1, x, y; i < N; ++i) {
		read(x, y);
		tr.add_edge(x, y);
		tr.add_edge(y, x);
	}
	// O(1);
	dfs(1);
	for (int i = 2; i <= N; ++i) if (fa[i] > i) dp[i] = -dp[i];
	dfs1(1);
	vector<int> s, t;
	// O(1);
	for (int i = 1; i <= N; ++i) if (ct[i] > 0) while (ct[i]--) s.push_back(i);
	else if (ct[i] < 0) while (ct[i]++) t.push_back(i);
	printf("%u\n", s.size());
	for (int i = 0; i < s.size(); ++i) printf("%d %d\n", t[i], s[i]);
	// cout << (-3 / 2);
	cerr << ((double) clock() / CLOCKS_PER_SEC) << '\n';
	return (0-0);
}
posted @ 2022-06-14 21:09  siriehn_nx  阅读(98)  评论(0编辑  收藏  举报