传送门:http://acm.sgu.ru/problem.php?problem=507
题意:给你一棵树,叶子有权值,求每个节点(除叶外)子树叶子两个之差最小值,若只有一个叶子的节点,输出2147483647
分析:启发式合并,set应用
#include <iostream>
#include <cstdio>
#include <iterator>
#include <set>
#include <vector>
#include <algorithm>
using namespace std;
#define INF 2147483647
const int maxn = 50005;
int v[maxn];
int n,m,k;
vector<int> g[maxn];
set<int> s[maxn];
set<int>::iterator pre,si,suc;
int Merge(set<int>& x,set<int>& y)
{
if(x.size()<y.size()) swap(x,y);
int tmp = INF;
for(si=y.begin();si!=y.end();si++)
{
pre = suc = x.lower_bound(*si);
if(pre!=x.begin()) pre --;
if(pre!=x.end()) tmp = min(tmp,abs(*si - *pre));
if(suc!=x.end()) tmp = min(tmp,abs(*si - *suc));
x.insert(*si);
}
return tmp;
}
void dfs(int u)
{
if(!g[u].size())
{
s[u].insert(v[u]);
v[u] = INF;
return;
}
v[u] = INF;
for(unsigned int i=0;i<g[u].size();i++)
{
int vv = g[u][i];
dfs(vv);
v[u] = min(v[u],v[vv]);
v[u] = min(v[u],Merge(s[u],s[vv]));
}
}
void solve()
{
for(int i=1; i<=n; i++)
{
g[i].clear();
s[i].clear();
}
for(int i=2; i<=n; i++)
{
scanf("%d",&k);
g[k].push_back(i);
}
for(int i=n-m+1; i<=n; i++)
{
scanf("%d",&v[i]);
}
dfs(1);
}
void output()
{
printf("%d",v[1]);
for(int i =2;i<=n-m;i++)
printf(" %d",v[i]);
puts("");
}
int main()
{
while(~scanf("%d %d",&n,&m))
{
solve();
output();
}
return 0;
}