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;
}

posted @   jt0007  阅读(5)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
点击右上角即可分享
微信分享提示