树学
很明显地可以使用换根思想简化暴力,先dfs求出以1为根的dpeth和,作为ans的初始值,然后再dfs2换根操作,当孩子和父亲身份互换时,我们可以由父亲的信息推出孩子作为根时的depth和。由此我们便可以避免每次换不同的根去暴力。
depth[j] = depth[s] - num[j] + (n - num[j] ) , 其中 j 是s的孩子,num[j] 为以 j 为根的树的大小。
#include<bits/stdc++.h>
using namespace std;
const int N = 1e6+7;
int n;
int h[N],e[N*2],ne[N*2],idx;
int depth[N]; //代表以i为根时的深度和
int num[N]; //代表以i为根时的树的大小(节点个数)
int ans;
void add(int a,int b){
e[idx] = b,ne[idx] = h[a],h[a] = idx++;
}
void dfs(int s,int f)
{
num[s] = 1;
depth[s] = depth[f] + 1;
for(int i=h[s];i!=-1;i=ne[i]){
int j = e[i];
if(j==f) continue;
dfs(j,s);
num[s] += num[j];
}
}
void Root(int s,int f)
{
for(int i=h[s];~i;i=ne[i]){
int j = e[i];
if(j==f) continue;
depth[j] = depth[s]-num[j] + n-num[j]; //以j为根时的深度和
ans = min(ans,depth[j]); //取最小即可
Root(j,s);
}
}
int main()
{
memset(h,-1,sizeof h);
scanf("%d",&n);
for(int i=1;i<n;i++){
int x,y;
scanf("%d%d",&x,&y);
add(x,y),add(y,x);
}
depth[0] = -1;
dfs(1,0);
for(int i=2;i<=n;i++) depth[1] += depth[i]; //以1为根的深度和
ans = depth[1];
Root(1,0);
cout<<ans<<endl;
return 0;
}
Accumulation Degree
题意:给一棵树,边权为可通过的流量值,求通过结点的最大的流量值。
思路:同样的,我们可以先求出以1为根时通过1的流量值,然后再换根操作。详细看注释吧~
#include<bits/stdc++.h>
using namespace std;
const int N = 1e6+7;
int n;
int h[N],e[N*2],ne[N*2],w[N*2],idx;
int dp[N]; //代表以i为根时的流量
int in[N];
int ans;
void add(int a,int b,int v){
e[idx] = b,w[idx] = v,ne[idx] = h[a],h[a] = idx++;
}
void dfs(int s,int f)
{
for(int i=h[s];i!=-1;i=ne[i]){
int j = e[i];
if(j==f) continue;
dfs(j,s);
if(in[j]==1) dp[s] += w[i] ; //当孩子是叶子结点时,就直接取最大流量直接累和即可
else dp[s] += min(w[i],dp[j]); //否则就比较边权和孩子的流量取最小值
}
}
void Root(int s,int f)
{
for(int i=h[s];i!=-1;i=ne[i]){
int j = e[i];
if(j==f) continue;
if(in[j]==1) dp[j] = w[i]; //当叶子结点为根时,累计流量就是它的边权;
else dp[j] += min(dp[s] - min(w[i],dp[j]) , w[i]); //否则就正常换根,画个图会很好推出来
ans = max(ans,dp[j]);
Root(j,s);
}
}
int main()
{
int T;
scanf("%d",&T);
while(T--){
memset(h,-1,sizeof h),idx=0; //多组
scanf("%d",&n);
for(int i=1;i<n;i++){
int x,y,z;
scanf("%d%d%d",&x,&y,&z);
add(x,y,z),add(y,x,z);
in[x]++ , in[y]++;
}
dfs(1,0);
ans = dp[1]; //记得初始化第一个根,wa了好几发,,,
Root(1,0);
printf("%d\n",ans);
memset(dp,0,sizeof dp); //多组
memset(in,0,sizeof in);
}
return 0;
}