A-啊啊啊啊啊_一起来做题~欢乐赛7 (nowcoder.com)
题目描述

样例
4 1 2 1 3 1 4
3
算法1
(换根dp)
分析:
- 大体的思路就是先以某个节点为根计算出一个权值
- 接着从这个节点开始移动
- 计算每次从当前节点u移动到其子节点v对答案的影响
- 影响就是减去以子节点v为根的子树所有节点经过边<u,v>的距离
- 加上除v为根节点的子树外的所有节点经过边<u,v>的距离
状态转移:
状态表示:为以u为根的子树的权值
树形dp部分:
解释:
为以v为根的子树大小,每个节点经过边<u,v>都有一个贡献
换根dp部分:
解释:- sz[v]先将以v为根的子树的影响消除,+ (n - sz[v]) 增加除以v为根的子树的节点外的点经过边<u,v>的贡献
细节:
每一条边的贡献不是单纯的1而是经过这条边的节点个数,可以说是子树大小
时间复杂度 &preview=true)
参考文献
C++ 代码
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
// #include <unordered_map>
#include <vector>
#include <queue>
#include <set>
#include <bitset>
#include <cmath>
#include <map>
#define x first
#define y second
#define P 131
#define lc u << 1
#define rc u << 1 | 1
using namespace std;
typedef long long LL;
const int N = 1000010;
const LL INF = 0x3f3f3f3f3f3f3f3fll;
int h[N],ne[N * 2],e[N * 2],idx;
LL f[N];
int sz[N];
LL ans;
int n;
void add(int a,int b)
{
e[idx] = b,ne[idx] = h[a],h[a] = idx ++;
}
void dfs1(int u,int father)
{
sz[u] = 1;
f[u] = 0;
for(int i = h[u];~i;i = ne[i])
{
int j = e[i];
if(j == father) continue;
dfs1(j,u);
f[u] += f[j] + sz[j];
sz[u] += sz[j];
}
}
void dfs2(int u,int father)
{
for(int i = h[u];~i;i = ne[i])
{
int j = e[i];
if(j == father) continue;
f[j] = f[u] - sz[j] + (n - sz[j]);
dfs2(j,u);
}
ans = min(ans,f[j]);
}
void solve()
{
scanf("%d",&n);
for(int i = 1;i <= n;i ++) h[i] = -1;
for(int i = 0;i < n - 1;i ++)
{
int a,b;
scanf("%d%d",&a,&b);
add(a,b);
add(b,a);
}
dfs1(1,0);
ans = f[1];
dfs2(1,0);
printf("%lld\n",ans);
}
int main()
{
int _ = 1;
// freopen("network.in","r",stdin);
// freopen("network.out","w",stdout);
// init(N - 1);
// std::ios_base::sync_with_stdio(0);
// cin.tie(0);
// cin >> _;
// scanf("%d",&_);
while(_ --)
{
// scanf("%lld%lld",&n,&m);
solve();
// test();
}
return 0;
}
京公网安备 11010502036488号