[北大集训2021] 小明的树

[北大集训2021] 小明的树

题意就不放了

给个题目链接

【北大集训2021】小明的树 - 题目 - Universal Online Judge (uoj.ac)

我们考虑,什么时候可能是合法的,那么应该是没有点亮的灯形成了一个连通块的时候,即两端都是未点亮的灯的时候边数=n-1-操作次数。

居然从有根树得到了无根树的限制。神奇。

然后,考虑合法的时候什么边会贡献答案,应该一端黑着,一端亮着的边会贡献一个答案。

我们可以对每个边单独考虑,然后计算他什么时候是贡献答案的,然后用线段树可以(按照时间为下标,维护一个(两端都是未点亮的灯的)合法边数(可以转化为区间最大值),还有这个合法情况的个数即可,还有区间求和)。

#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 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; }
template<typename T>
inline void read(T &x) {
	x = 0;
	bool f = 0;
	char ch = getchar();
	while (!isdigit(ch)) f = ch == '-', ch = getchar();
	while (isdigit(ch)) x = x * 10 + ch - '0', ch = getchar();
	if (f) x = -x;
}
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 = 524288, 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;
};
inline int ls(int k) { return k << 1; }
inline int rs(int k) { return k << 1 | 1; }
// 为什么别人都可以
// 单恋一枝花
int N, M, SZ, B[MAXN], A[MAXN];
pair<int, int> e[MAXN];
int mx[MAXN * 4], ct[MAXN * 4], tag[MAXN * 4][2];
long long s[MAXN * 4];
inline void pushup(int k) {
	s[k] = ct[k] = 0;
	mx[k] = max(mx[ls(k)], mx[rs(k)]);
	if (mx[k] == mx[ls(k)]) {
		ct[k] += ct[ls(k)];
		s[k] += s[ls(k)];
	}
	if (mx[k] == mx[rs(k)]) {
		ct[k] += ct[rs(k)];
		s[k] += s[rs(k)];
	}
}
void build(int nw, int l, int r) {
	if (l == r) {
		mx[nw] = -(N - r - 1);
		ct[nw] = 1;
		return;
	}
	int mid = (l + r) / 2;
	build(ls(nw), l, mid);
	build(rs(nw), mid + 1, r);
	pushup(nw);
}
// 保证 ql <= qr
inline void addtag(int o, int nw, int k) {
	tag[nw][o] += k;
	if (!o) mx[nw] += k;
	else s[nw] += k * ct[nw];
}
inline void pushdown(int nw) {
	for (int i = 0; i < 2; ++i) if (tag[nw][i]) {
		addtag(i, ls(nw), tag[nw][i]);
		addtag(i, rs(nw), tag[nw][i]);
		tag[nw][i] = 0;
	}
	return;
}
void mfy(int nw, int l, int r, int ql, int qr, int k, int o) {
	if (ql <= l && r <= qr) return addtag(o, nw, k);
	pushdown(nw);
	int mid = (l + r) / 2;
	if (ql <= mid) mfy(ls(nw), l, mid, ql, qr, k, o);
	if (mid < qr) mfy(rs(nw), mid + 1, r, ql, qr, k, o);
	pushup(nw);
}
void upd(int x, int y, int k) {
	if (B[x] > B[y]) swap(x, y);
	if (B[x] > 1) mfy(1, 1, SZ, 1, B[x] - 1, k, 0);
	mfy(1, 1, SZ, B[x], B[y] - 1, k, 1);
}
int main() {
	// freopen("715.in", "r", stdin);
	// freopen("715.out", "w", stdout);
	qwq::init(20050112);
	read(N, M);
	for (int i = 1; i < N; ++i) read(e[i].first, e[i].second);
	A[N] = 1;
	for (int i = 1; i < N; ++i) read(A[i]);
	for (int i = 1; i <= N; ++i) B[A[i]] = i;
	build(1, 1, SZ = N - 1);
	for (int i = 1; i < N; ++i) upd(e[i].first, e[i].second, 1);
	printf("%lld\n", s[1]);
	for (int i = 1, x, y; i <= M; ++i) {
		read(x, y);
		upd(x, y, -1);
		read(x, y);
		upd(x, y, 1);
		printf("%lld\n", s[1]);
	}
	// cout << (-3 / 2);
	cerr << ((double) clock() / CLOCKS_PER_SEC) << '\n';
	return (0-0);
}
posted @ 2022-04-05 23:37  siriehn_nx  阅读(190)  评论(0编辑  收藏  举报