Luogu P8990
注意到直接根据题目的条件判断树是否美丽并不容易。考虑未被点亮的点,可以发现一棵树是美丽的当且仅当未被点亮的点形成一个连通块。
有一个结论是,对于一个森林,点数减边数等于连通块的个数。
因此树是美丽的当且仅当 “未被点亮的节点的个数”减去“两端都未被点亮的边的个数”
同时根据
如果我们按顺序执行点亮操作,那么每个时刻的
接下来考虑 link-cut 操作,先考虑断掉一条边
同理,如果连上一条边
于是转化成了一个线段树问题。具体地,对于线段树每个节点
时间复杂度
#include<bits/stdc++.h>
#define endl '\n'
#define rep(i, s, e) for(int i = s, i##E = e; i <= i##E; ++i)
#define per(i, s, e) for(int i = s, i##E = e; i >= i##E; --i)
#define F first
#define S second
#define int ll
#define gmin(x, y) (x = min(x, y))
#define gmax(x, y) (x = max(x, y))
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef long double f128;
typedef pair<int, int> pii;
constexpr int N = 5e5 + 5;
int n, m, a[N], t[N];
struct edge {
int u, v;
} e[N];
struct node {
int mn, sum, cnt, t1, t2;
} nd[N * 4];
#define ls (p << 1)
#define rs (p << 1 | 1)
void upd(int p, int v, int w) {
nd[p].mn += v;
nd[p].t1 += v;
nd[p].sum += nd[p].cnt * w;
nd[p].t2 += w;
}
void pushdown(int p) {
if(nd[p].t1 || nd[p].t2) {
upd(ls, nd[p].t1, nd[p].t2);
upd(rs, nd[p].t1, nd[p].t2);
nd[p].t1 = nd[p].t2 = 0;
}
}
void pushup(int p) {
if(nd[ls].mn < nd[rs].mn) nd[p].mn = nd[ls].mn, nd[p].sum = nd[ls].sum, nd[p].cnt = nd[ls].cnt;
else if(nd[ls].mn > nd[rs].mn) nd[p].mn = nd[rs].mn, nd[p].sum = nd[rs].sum, nd[p].cnt = nd[rs].cnt;
else nd[p].mn = nd[ls].mn, nd[p].sum = nd[ls].sum + nd[rs].sum, nd[p].cnt = nd[ls].cnt + nd[rs].cnt;
}
void build(int p, int l, int r) {
if(l == r) {
nd[p].mn = n - l;
nd[p].sum = l;
nd[p].cnt = 1;
return;
}
int mid = (l + r) / 2;
build(ls, l, mid), build(rs, mid + 1, r);
pushup(p);
}
void add(int p, int l, int r, int ql, int qr, int v, int w) {
if(l > qr || r < ql) return;
if(ql <= l && qr >= r) return upd(p, v, w);
pushdown(p);
int mid = (l + r) / 2;
add(ls, l, mid, ql, qr, v, w);
add(rs, mid + 1, r, ql, qr, v, w);
pushup(p);
}
signed main() {
#ifdef ONLINE_JUDGE
ios::sync_with_stdio(0);
cin.tie(0), cout.tie(0);
#endif
cin >> n >> m;
build(1, 1, n - 1);
rep(i, 1, n - 1) cin >> e[i].u >> e[i].v;
rep(i, 1, n - 1) cin >> a[i], t[a[i]] = i;
t[1] = n;
rep(i, 1, n - 1) {
int u = e[i].u, v = e[i].v;
add(1, 1, n - 1, 1, min(t[u], t[v]) - 1, -1, 0);
add(1, 1, n - 1, max(t[u], t[v]), n - 1, 0, -1);
}
cout << (nd[1].mn == 1 ? nd[1].sum : 0) << endl;
while(m--) {
int u, v, x, y;
cin >> u >> v >> x >> y;
add(1, 1, n - 1, 1, min(t[u], t[v]) - 1, 1, 0);
add(1, 1, n - 1, max(t[u], t[v]), n - 1, 0, 1);
add(1, 1, n - 1, 1, min(t[x], t[y]) - 1, -1, 0);
add(1, 1, n - 1, max(t[x], t[y]), n - 1, 0, -1);
cout << (nd[1].mn == 1 ? nd[1].sum : 0) << endl;
}
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
· AI与.NET技术实操系列(六):基于图像分类模型对图像进行分类