ybtoj树形DP习题
路径求和
显然每个点被经过的次数等于它分成的两个子树叶子节点与大小的乘积
代码:
#include<bits/stdc++.h>
#define int long long
using namespace std;
int n,m;
const int maxn=2e5+5;
int dep[maxn];
int head[maxn];
int to[maxn];
int nxt[maxn];
int w[maxn];
int tag[maxn];
int lev[maxn];
int cd[maxn];
int cnt;
int sum;
void add(int x,int y,int z){
to[++cnt]=y;
nxt[cnt]=head[x];
w[cnt]=z;
head[x]=cnt;
}
void dfs(int x,int f){
tag[x]=1;
if(cd[x]==1) lev[x]++;
for(int i=head[x];i;i=nxt[i]){
int v=to[i];
if(v==f) continue;
dfs(v,x);
tag[x]+=tag[v];
lev[x]+=lev[v];
}
}
void dfs2(int x,int f){
for(int i=head[x];i;i=nxt[i]){
int v=to[i];
if(v==f) continue;
dfs2(v,x);
sum+=w[i]*(tag[v]*(lev[1]-lev[v])+(tag[1]-tag[v])*(lev[v]));
}
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cin>>n>>m;
for(int i=1;i<=m;i++){
int x,y,z;
cin>>z>>x>>y;
add(x,y,z);
add(y,x,z);
cd[x]++;
cd[y]++;
}
dfs(1,0);
dfs2(1,0);
cout<<sum;
return 0;
}
树上移动
首先考虑一个点,显然它只能在最后一条路径经过一次,剩下的经过两次
对于两个点他可以在一个点的子树中选择两个最长链走一次剩下的走两次
#include<bits/stdc++.h>
using namespace std;
const int maxn=2e5+5;
int head[maxn];
int to[maxn];
int nxt[maxn];
int w[maxn];
int cd[maxn];
int siz[maxn];
int cnt;
int n,s;
int maxx[maxn];
int sec[maxn];
void add(int x,int y,int z){
to[++cnt]=y;
nxt[cnt]=head[x];
w[cnt]=z;
head[x]=cnt;
}
void dfs(int x,int f){
for(int i=head[x];i;i=nxt[i]){
int v=to[i];
if(v==f) continue;
dfs(v,x);
if(w[i]+maxx[v]>maxx[x]){
sec[x]=maxx[x];
maxx[x]=w[i]+maxx[v];
}
else if(w[i]+maxx[v]>sec[x]){
sec[x]=w[i]+maxx[v];
}
}
}
int ans1,ans2;
signed main(){
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cin>>n>>s;
for(int i=1;i<n;i++){
int a,b,c;
cin>>a>>b>>c;
add(a,b,c);
add(b,a,c);
cd[a]++;
cd[b]++;
ans1+=c*2;
ans2+=c*2;
}
dfs(s,0);
cout<<ans1-maxx[s];
cout.put('\n');
int maxxx=0;
for(int i=1;i<=n;i++) maxxx=max(maxxx,maxx[i]+sec[i]);
cout<<ans2-maxxx;
return 0;
}
块的计数
正难则反,考虑所有的组合与不合法的组合,设组合数为f
f[x]=f[x]∗(f[v]+1)
要包括这棵子树内什么都不选的情况
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int maxn=2e5+5;
const int mod=998244353;
int maxx=-INT_MAX;
int head[maxn];
int nxt[maxn];
int to[maxn];
int c[maxn];
int f[maxn];
int n;
int val[maxn];
int cnt;
int ans;
void add(int x,int y){
to[++cnt]=y;
nxt[cnt]=head[x];
head[x]=cnt;
}
void dfs(int x,int ff){
c[x]=1;
if(val[x]!=maxx) f[x]=1;
for(int i=head[x];i;i=nxt[i]){
int v=to[i];
if(v==ff) continue;
dfs(v,x);
c[x]=c[x]*(c[v]+1)%mod;
f[x]=f[x]*(f[v]+1)%mod;
}
ans=(ans+c[x]-f[x]+mod)%mod;
}
signed main(){
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cin>>n;
for(int i=1;i<=n;i++){
cin>>val[i];
maxx=max(val[i],maxx);
}
for(int i=1;i<n;i++){
int a,b;
cin>>a>>b;
add(a,b);
add(b,a);
}
dfs(1,0);
cout<<ans;
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)