目录
1、距离和
//
// 距离和
#include<bits/stdc++.h>
using namespace std;
const int N = 100005;
#define ll long long
ll n,f[N],v[N],size[N]; // 以 i 为根节点时,i的子节点到i的路径之和
int head[N];
struct edge{
int to,next;
}e[N<<1];
int cnt = 0;
bool vis[N];
inline void up(int i){
size[i] = 1;
vis[i] = 1;
for(int x = head[i]; x ; x = e[x].next){
int to = e[x].to;
if(!vis[to]){
up(to);
size[i] += size[to];
f[i] += f[to];
}
}
f[i] += size[i] -1;
}
inline void down(int i){
vis[i] = 1;
for(int x = head[i]; x ; x = e[x].next){
int to = e[x].to;
if(!vis[to]){// f[i] + v[i] : 以 i 为根节点的路径和 !!!!!
v[to] = v[i] + f[i] - f[to] - size[to] + n - size[to];
down(to); // 求子v[]时,需要用到父v[],所以是先计算,再递归调用down
}
}
}
inline void makelist(int u,int v){
e[++cnt].to = v;
e[cnt].next = head[u];
head[u] = cnt;
}
int main(){
memset(head,0,sizeof(head));
cin>>n;
for(int i = 1; i < n; ++i){
int u,v;cin>>u>>v;
makelist(u,v);
makelist(v,u);
}
memset(vis,0,sizeof(vis));
up(1); // 求出f[i] 和 size[i]
memset(vis,0,sizeof(vis));
down(1); // 求v[i]
for(int i = 1; i <= n; ++i){
printf("%lld\n", f[i] + v[i]);
// f[i] : 以 i 为根节点,其子节点到根节点的路径和 (注意:这里没有换根,换根只是一种思想)
// v[i] : i节点的父节点x作为i的子节点时,x节点那一部分对i节点的路径贡献
}
return 0;
}
2、流
//
// 距离和
#include<bits/stdc++.h>
using namespace std;
const int N = 100005;
#define ll long long
ll n,f[N],v[N]; // 以 i 为根节点时,i的子节点到i的路径之和
int head[N];
struct edge{
int to,w,next;
}e[N<<1];
// f[j] : 以j为根节点的子树的消化能力 w : 管道的流量限制
int cnt = 0;
bool vis[N];
inline void up(int i){
vis[i] = 1;
bool sign = 1; // 是否是叶子节点
for(int x = head[i]; x ; x = e[x].next){
int to = e[x].to;
int w = e[x].w;
if(!vis[to]){
up(to);
f[i] += min(1ll * w,f[to]);
sign = 0;
}
}
if(sign)f[i] = 1<<30;
}
inline void down(int i){
vis[i] = 1;
for(int x = head[i]; x ; x = e[x].next){
int to = e[x].to;
int w = e[x].w;
if(!vis[to]){
if(v[i] + f[i] == min(1ll*w,f[to])) // i是叶子节点
v[to] = w;
else
v[to] = min(f[i] + v[i] - min(1ll*w,f[to]),1ll*w);
down(to); // 求子v[]时,需要用到父v[],所以是先计算,再递归调用down
}
}
}
inline void makelist(int u,int v,int w){
e[++cnt].to = v;
e[cnt].w = w;
e[cnt].next = head[u];
head[u] = cnt;
}
int main(){
memset(head,0,sizeof(head));
cin>>n;
for(int i = 1; i < n; ++i){
int u,v,w;scanf("%d%d%d",&u,&v,&w);
makelist(u,v,w);
makelist(v,u,w);
}
memset(vis,0,sizeof(vis));
up(1); // 求出f[i] 和 size[i]
memset(vis,0,sizeof(vis));
down(1);
for(int i = 1; i <= n; ++i){
if(f[i]!=1<<30)
printf("%lld\n", f[i] + v[i]);
else
printf("%lld\n", v[i]);
}
return 0;
}
3、最长路径
//
// 距离和 无根数 选根
#include<bits/stdc++.h>
using namespace std;
const int N = 100005;
#define ll long long
int f[N][2][2],v[N];
// f[N][2][2] N : 每个节点; 二维0:最长 1:次长 ; 三维0:路径长度 1:从哪个点上来的。
int head[N];
struct edge{
int to,next;
}e[N<<1];
int cnt = 0;
int n;
bool vis[N];
inline void up(int i){
vis[i] = 1;
for(int x = head[i]; x ; x = e[x].next){
int to = e[x].to;
if(!vis[to]){
up(to);
if(f[to][0][0] + 1 > f[i][0][0])
f[i][1][0] = f[i][0][0], f[i][1][1] = f[i][0][1], f[i][0][0] = f[to][0][0] + 1, f[i][0][1] = to;
else if(f[to][0][0] + 1 > f[i][1][0])
f[i][1][0] = f[to][0][0] + 1, f[i][1][1] = to;
}
}
}
inline void down(int i){
vis[i] = 1;
for(int x = head[i]; x ; x = e[x].next){
int to = e[x].to;
if(!vis[to]){
if(f[i][0][1] == to)
v[to] = max(v[i],f[i][1][0]) + 1;
else
v[to] = max(f[i][0][0],v[i]) + 1;
down(to); // 求子v[]时,需要用到父v[],所以是先计算,再递归调用down
}
}
}
inline void makelist(int u,int v){
e[++cnt].to = v;
e[cnt].next = head[u];
head[u] = cnt;
}
int main(){
memset(head,0,sizeof(head));
cin>>n;
for(int i = 1; i < n; ++i){
int u,v;cin>>u>>v;
makelist(u,v);
makelist(v,u);
}
memset(vis,0,sizeof(vis));
up(1); // 求出f[i] 和 size[i]
memset(vis,0,sizeof(vis));
down(1);
for(int i = 1; i <= n; ++i){
printf("%d\n", f[i][0][0] + f[i][1][0] + v[i] - min(min(f[i][0][0],f[i][1][0]),v[i]));
}
return 0;
}