1 solutions
-
0
Guest MOD
-
0
我们考虑如果一颗子树是阴阳子树,那么这颗子树能够产生贡献的时间区间段是多少 我们考虑 出子树 中最早变成斑马子树的时间戳,最晚变成非斑马子树的时间戳 那么 的时间段上 的贡献一直为 ,我们考虑差分,最后前缀和统计答案即可
#include <iostream> #include <vector> using namespace std; const int N = 2e5 + 10; // 题目最大节点数(n≤2e5) int n; int t[N]; // t[u]:节点u被染色的时间(第i次操作染p[i],时间i从1到n) int mi[N], mx[N];// mi[u]/mx[u]:以u为根的子树中最小/最大时间戳 int ans[N]; // 差分数组,用于统计每个时间点的阴阳子树数量 vector<int> g[N];// 树的邻接表 // DFS遍历,计算每个子树的mi和mx(后序遍历) void dfs(int u, int par) { mi[u] = mx[u] = t[u]; // 初始化为当前节点的时间戳 for (int v : g[u]) { if (v == par) continue; // 跳过父节点 dfs(v, u); mi[u] = min(mi[u], mi[v]); // 合并子树的mi mx[u] = max(mx[u], mx[v]); // 合并子树的mx } // 差分操作:当前子树的时间区间是 [mi[u], mx[u]] ans[mi[u]]++; ans[mx[u]]--; } void solve() { cin >> n; // 构建树(节点2~n的父节点) for (int i = 2; i <= n; ++i) { int u; cin >> u; g[u].push_back(i); // 无向边(邻接表) g[i].push_back(u); } // 读取染色顺序p,并记录每个节点的染色时间t[u] for (int i = 1; i <= n; ++i) { int u; // 第i次操作染节点u cin >> u; t[u] = i; // 时间从1到n } // 从根节点1开始DFS dfs(1, 0); // 计算前缀和,得到每个时间点的阴阳子树数量 int current = 0; for (int i = 1; i <= n; ++i) { current += ans[i]; cout << current << " \n"[i == n]; // 最后一个数后换行 } } int main() { ios::sync_with_stdio(false); // 加速输入输出 cin.tie(nullptr); solve(); return 0; }
- 1
Information
- ID
- 1464
- Time
- 2000ms
- Memory
- 256MiB
- Difficulty
- 7
- Tags
- (None)
- # Submissions
- 25
- Accepted
- 8
- Uploaded By