[北大集训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);
}