题意:给你一个图,每次选一个点涂成黑色,顺便获得权值(该节点的树上白色点的数目),每次只能选择与黑色相邻的白色节点涂色,求所有操作之后的权值和
思路:以每个节点开始涂色的权值和为定值,则遍历所有节点为根节点的情况的权值,取最大值则为答案,dp求每种根的情况的答案d[i]=d[son]+sz[i],sz[i]为树的节点数,dfs所有子节点情况并根转移,d[u]~d[v]转化
知识点:换根dp、vector、auto、树dfs
#include<bits/stdc++.h>
using namespace std;
const int N=200005;
vector<int> vec[N];//动态数组存子节点
long long int d[N];//保存每结点子树的权值总和 即 题目所求
int n,sz[N];//保存该子树的节点数
long long int ans=0;
void dfs(int u,int fa)//求1节点的权值
{
sz[u]=1;//每个子树的节点数初始化为1
for(auto v : vec[u])//用 v 表示 子节点
{
if(v==fa) continue;//dfs体现 如果 u 的子节点 v 为 u 的父节点 fa
// (fa已经涂色) 则跳过此子节点
dfs(v,u);//求子节点的权值d[v] 和 子树节点数sz[v]
sz[u]+=sz[v];//把每一个子树大小相加
d[u]+=d[v];//该点子节点权值 相加
}
d[u]+=sz[u];//dp体现 该点权值 加 所有子节点的权值
}
void dfs1(int u,int fa)
{
ans=max(ans,d[u]);//在u节点为第一次涂色情况时的权值大小 ,取大值更新ans
for( auto v: vec[u]) //换根
{
if(v==fa) continue;//dfs体现 父节点已经算过 跳过
long long temp=d[u]-sz[v]-d[v];//p体现
//d[1]=d[2]+d[4]+1+sz[2]+sz[4] -> d[4]+1+sz[4]
//即 d[1]=d[1]-d[2]-sz[2] ->temp=d[u]= d[u]-d[v]-sz[v]
d[v]=d[v]+(n-sz[v])+temp;//p体现
//d[2]=d[3]+d[5]+d[6]+1+sz[3]+sz[5]+sz[6] -> d[3]+d[5]+d[6] ( +d[1] / +temp )+1+sz[3]+sz[5]+sz[6]+(n-sz[1])
dfs1(v,u);//继续向子节点扫描
}
}
int main()
{
cin>>n;
for(int i=0;i<n-1;i++)
{
int x,y;
scanf("%d%d",&x,&y);
vec[x].push_back(y);
vec[y].push_back(x);
//记录每两个节点的联系
}
dfs(1,0);//求出1号节点的权值 初始化
dfs1(1,0);//换根
cout<<ans<<endl;
}
小G砍树
链接:https://ac.nowcoder.com/acm/contest/375/C
来源:牛客网
时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 262144K,其他语言524288K
64bit IO Format: %lld题目描述
给你一棵n个节点的带标号无根树。每次,你可以选择一个度数为1的节点并将它从树上移除。问总共有多少种不同的方式能将这棵树删到只剩 1 个点。两种方式不同当且仅当至少有一步被删除的节点不同。
输入描述:
第一行一个数n。接下来n-1行,描述这棵树的n-1条边。节点编号为1~n。
输出描述:
一行一个正整数,表示方案数对998244353取模的值。
示例1
输入
4 1 2 1 3 1 4
输出
12
备注:
n≤100000n≤100000
题意:求不同根的情况时,排列树的和
思路:求出d[1]根为1时的排列数,d[1]=n!/sz[1~n](排列消序),然后换根d[v]转换d[v]=d[u]*(sz[u]/sz`[u])*(sz[v]/sz`[v]) 其中sz[u]=n,sz`[v]=n,sz`[u]=n-sz[v];化简后:d[v]=d[u]*sz[v]/(n-sz[v]))第一次dfs求出sz[1~n],d[1]=n!/sz[1~n],第二次dfs换根求d[2~n],ans+=d[1~n],输出ans即答案。
核心:dfs 全排列
#include<bits/stdc++.h>
using namespace std;
#define mod 998244353
const int N=100005;
vector<int> vect[100005];
long long int n,sz[N],d[N],ans=0;
void dfs(int u,int fa)
{
sz[u]+=1;
for(auto z : vect[u])
{
if(z==fa) continue;
dfs(z,u);
sz[u]=(sz[u]+sz[z])%mod;
}
}
void dfs2(int u,int fa)
{
long long int niyuan(long long int a,long long int b);
ans=(ans+d[u])%mod;
for(auto v: vect[u])
{
if(v==fa) continue;
d[v]=niyuan((d[u]*sz[v])%mod,n-sz[v]);
dfs2(v,u);
}
}
long long int niyuan(long long int a,long long int b)
{
long long int qiuck(int c);
return a*qiuck(b)%mod;
}
long long int qiuck(int b)//快速幂
{
int y=mod-2;
long long int bb=1;
long long int x=b;
while(y)
{
if(y&1) bb=(bb*x)%(mod);
x=(x*x)%(mod);
y>>=1;
}
return bb;
}
int main()
{
cin>>n;
long long cj=1,cjj=1;
for(int i=0;i<n-1;i++)
{
long long int x,y;
scanf("%lld%lld",&x,&y);
vect[x].push_back(y);
vect[y].push_back(x);
cj=(cj*(i+2))%mod;
}
dfs(1,0);
for(int i=1;i<=n;i++)
{
cjj=((cjj%mod)*(sz[i])%mod)%mod;
}
d[1]=niyuan(cj,cjj);//逆元
dfs2(1,0);
cout<<ans<<endl;
}