SGU507. Treediff(樹上啟發式合併/set)
507. Treediff
Time limit per test: 0.25 second(s)
Memory limit: 262144 kilobytes
input: standard
output: standard
Andrew has just made a breakthrough in complexity theory: he thinks that he can prove P=NP if he can get a data structure which allows to perform the following operation quickly. Naturally, you should help him complete his brilliant research. Consider a rooted tree with integers written in the leaves. For each internal (non-leaf) node v
Input
The first line of the input file contains two integers n and m — overall number of nodes in the tree and number of leaves in the tree respectively. . All nodes are numbered from 1 to n
Output
Output one line with n - m integers: for each internal node of the tree output the minimum absolute difference between pairs of values written in the leaves of its subtree. If there is only one leaf in the subtree of some internal node, output number 231 - 1 for that node. Output the answers for the nodes in order from node number 1 to n - m.
Example(s)
sample input |
sample output |
---|---|
5 4 1 1 1 1 1 4 7 9 |
2 |
sample input |
sample output |
---|---|
5 4 1 1 1 1 1 4 7 10 |
3 |
sample input |
sample output |
---|---|
7 4 1 2 1 2 3 3 2 10 7 15 |
3 3 8 |
sample input |
sample output |
---|---|
2 1 1 100 |
2147483647 |
同樣是dsu on tree的典型題,整體思想是用set去維護當前以rt為根子樹的葉子結點。先搜一遍輕兒子,清空set後再搜重兒子,此時set儲存的是重兒子對應的子樹的葉子結點。這時候再暴力dfs一遍輕兒子,每當搜到一個葉子結點的時候就可以更新rt的答案了(插入set然後與其他相鄰的葉子結點的val值計算更新答案)。
#include <iostream>
#include <set>
#include <cstring>
#define N 50005
using namespace std;
int n, m, tot = 0, head[N], ver[2 * N], Next[2 * N];
int val[N];
int sz[N], son[N];
int ans[N];
set<int> st;
int hson = 0;
void add(int x, int y) {
ver[++tot] = y, Next[tot] = head[x], head[x] = tot;
}
void dfs1(int x, int pre) {
sz[x] = 1;
int mxsz = -1;
for(int i = head[x]; i; i = Next[i]) {
int y = ver[i];
if(y == pre) continue;
dfs1(y, x);
sz[x] += sz[y];
if(sz[y] > mxsz) {
son[x] = y;
mxsz = sz[y];
}
}
}
void Delete() {
st.clear();
}
void process(int x, int pre, int rt) {
if(val[x] != 0x3f3f3f3f) {//葉子結點
if(st.find(val[x]) != st.end()) {
ans[rt] = 0;
} else {
st.insert(val[x]);
set<int>::iterator it = st.find(val[x]);
if(it == st.begin()) {
set<int>::iterator it1 = ++it;
it--;
if(it1 != st.end()) {
ans[rt] = min(ans[rt], abs((*it) - (*it1)));
}
} else {
set<int>::iterator it1 = ++it;
it--;
set<int>::iterator it2 = --it;
it++;
if(it1 != st.end()) {
ans[rt] = min(ans[rt], abs((*it) - (*it1)));
}
ans[rt] = min(ans[rt], abs((*it) - (*it2)));
}
}
} else {
for(int i = head[x]; i; i = Next[i]) {
int y = ver[i];
if(y == pre) continue;
process(y, x, rt);
}
}
}
void dfs2(int x, int pre) {
for(int i = head[x]; i; i = Next[i]) {
int y = ver[i];
if(y == pre || y == son[x]) continue;
dfs2(y, x), Delete();
}
if(son[x]) {
dfs2(son[x], x);
ans[x] = min(ans[x], ans[son[x]]);
}
for(int i = head[x]; i; i = Next[i]) {
int y = ver[i];
if(y == pre || y == son[x] && val[y] == 0x3f3f3f3f) continue;//y == son[x] && val[y] == 0x3f3f3f3f 表示不是葉子的重兒子才不搜
process(y, x, x);
}
}
int main() {
cin >> n >> m;
memset(ans, 0x3f3f3f3f, sizeof(ans));
memset(val, 0x3f3f3f3f, sizeof(val));//因為葉子結點的值可能為0
for(int i = 2; i <= n; i++) {
int fa;
cin >> fa;
add(fa, i);
add(i, fa);
}
for(int i = n - m + 1; i <= n; i++) {
cin >> val[i];
}
dfs1(1, 0);
dfs2(1, 0);
for(int i = 1; i <= n - m; i++) {
if(ans[i] != 0x3f3f3f3f) cout << ans[i] << " ";
else cout << 2147483647 << " ";
}
return 0;
}