树形DP的一些题

问题1

(http://zhengruioi.com/problem/1030)
\(n\) 个点的树,点有点权,定义一个连通块的贡献为其中所有点的点权和的平方。现在要求所有连通块的贡献之和。\(n\leq 5\times 10^5\)

sol:

考虑把平方式展开,\((a+b)^2=a^2+b^2+2ab\) 那么实质上就是要维护三个数组\(f[x], g[x], h[x]\),分别表示\(x\) 子树所有连通块权值和的平方,权值的和,还有连通块的个数。转移就很简单了。

#include <bits/stdc++.h>
#define ll long long
using namespace std;
inline int read(){
    int x=0;char c=getchar();
    while(c<'0'||c>'9') c=getchar();
    while(c>='0'&&c<='9') x=(x<<1)+(x<<3)+c-'0',c=getchar();
    return x;
}
const int N=500005,mod=998244353;
ll f[N],g[N],h[N],ans;
int n,w[N],ver[N<<1],nxt[N<<1],head[N],tot;
inline void link(int x,int y){ver[++tot]=y;nxt[tot]=head[x];head[x]=tot;}
void dfs(int x,int la){
    h[x]=1;g[x]=w[x];f[x]=1ll*w[x]*w[x]%mod;
    for(int i=head[x];i;i=nxt[i]){
        int y=ver[i];
        if(y==la) continue;
        dfs(y,x);
        f[x]=(f[x]+f[x]*h[y]%mod+g[x]*g[y]*2%mod+f[y]*h[x]%mod)%mod;
        g[x]=(g[x]+g[x]*h[y]%mod+g[y]*h[x]%mod)%mod;
        h[x]=(h[x]+h[x]*h[y]%mod)%mod;
    }
    ans=(ans+f[x])%mod;
}
int main(){
    n=read();
    for(int i=1;i<=n;i++) w[i]=read();
    for(int i=1;i<n;i++){
        int x=read(),y=read();
        link(x,y);link(y,x);
    }
    dfs(1,0);
    printf("%d\n",ans);
    return 0;
}

问题2

\(n\) 个点的树,点有点权,定义一条简单路径的贡献为其中所有点的点权和的平方。现在要求所有简单路径的贡献之和。\(n\leq 5\times 10^5\)

sol:

还是维护这些东西,但转移就相对没有那么好写了。其实道理是一样的。

问题3

(http://zhengruioi.com/contest/232/problem/595)
\(n\) 个点的树,边有边权,现在要按一个排列访问所有节点,从一个点\(u\) 到\(v\) 消耗的体力为\(u\) 到\(v\) 的简单路径上的所有边的长度的乘积,设一个方案一共消耗的体力为每次从一个点到另一个点消耗的体力之和。现在要求所有排列耗费体力之和。\(n\leq 5\times 10^5\)

sol:

真的不敢想象曾经普及组的我竟在模拟赛上切了这一题。因为是全排列,所以每一个点对\((u,v)\) 都会被算\((n-1)!\times 2\) 遍。考虑如何求所有\((u,v)\) 之和。维护\(f[x], g[x]\) 分别表示\(x\) 子树内使\(x\) 度为\(1\) 的路径,使\(x\) 度为\(2\) 的路径。转移见代码。

#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int N=500005,mod=998244353;
int n,ver[N<<1],nxt[N<<1],head[N],tot=1;
ll f[N],edge[N<<1],g[N];
void add(int x,int y,int z){ver[++tot]=y;edge[tot]=z;nxt[tot]=head[x];head[x]=tot;}
void dp(int x,int la){
    for(int i=head[x];i;i=nxt[i]){
        int y=ver[i];
        if(y==la) continue;
        dp(y,x);
        g[x]=(g[x]+edge[i]*f[y]%mod*f[x])%mod;
        f[x]=(f[x]+edge[i]*f[y]%mod)%mod;
    }
    f[x]++;
}
int main(){
    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);
    }
    dp(1,0);
    long long ans=0,step=1;
    for(int i=1;i<=n;i++) ans=(ans+g[i]+f[i]-1)%mod;
    for(int i=1;i<=n-1;i++) step=(step*i)%mod;
    printf("%lld\n",ans*step*2%mod);
    return 0;
}

CF1249F

(http://codeforces.com/contest/1249/problem/F)
\(n\) 个点的树和一个限制\(k\),点有点权,现在要选出一个点集,满足任意两个点的距离严格大于\(k\),并使得点权之和最大,求最大值。\(n,k\leq 200\)

sol:

原文地址:https://www.cnblogs.com/zxynothing/p/11780515.html

时间: 2024-11-13 08:04:30

树形DP的一些题的相关文章

HihoCoder1050 树中的最长路 树形DP第三题(找不到对象)

题意:求出的树中距离最远的两个结点之间相隔的距离. 水题一道,以前只会用路的直径来解. 代码如下: #include<cstdio> #include<cstdlib> #include<cstring> #include<iostream> #include<memory> #include<algorithm> using namespace std; const int maxn=200010; int dis[maxn],La

HihoCoder1041 国庆出游 树形DP第四题

小Hi和小Ho准备国庆期间去A国旅游.A国的城际交通比较有特色:它共有n座城市(编号1-n):城市之间恰好有n-1条公路相连,形成一个树形公路网.小Hi计划从A国首都(1号城市)出发,自驾遍历所有城市,并且经过每一条公路恰好两次--来回各一次--这样公路两旁的景色都不会错过. 令小Hi苦恼的是他的小伙伴小Ho希望能以某种特定的顺序游历其中m个城市.例如按3-2-5的顺序游历这3座城市.(具体来讲是要求:第一次到达3号城市比第一次到达2号城市早,并且第一次到达2号城市比第一次到达5号城市早). 小

POJ 1849 Two(树的直径--树形DP)(好题)

大致题意:在某个点派出两个点去遍历所有的边,花费为边的权值,求最少的花费 思路:这题关键好在这个模型和最长路模型之间的转换,可以转换得到,所有边遍历了两遍的总花费减去最长路的花费就是本题的答案,要思考,而且答案和派出时的起点无关 求最长路两遍dfs或bfs即可,从任意点bfs一遍找到最长路的一个终点,再从这个终点bfs找到起点 //1032K 79MS C++ 1455B #include<cstdio> #include<iostream> #include<cstring

CF482D Random Function and Tree 树形DP + 思维 + 神题

Code: #include<bits/stdc++.h> #define ull unsigned long long #define MOD 1000000007 #define ll long long #define maxn 120000 using namespace std; void setIO(string s) { string in=s+".in"; string out=s+".out"; freopen(in.c_str(),&

HDU 2196 Computer 树形DP 经典题

给出一棵树,边有权值,求出离每一个节点最远的点的距离 树形DP,经典题 本来这道题是无根树,可以随意选择root, 但是根据输入数据的方式,选择root=1明显可以方便很多. 我们先把边权转化为点权,放在数组cost中 令tree(i)表示以节点i为根的子树 对于节点i,离该节点最远的点要不就是在tree(i)中,要不就是在father(i)上面 令: dp[i][1] : 在子树tree(i)中,离i最远的距离 dp[i][2] : 在子树tree(i)中,离i第二远的距离 (递推的时候需要)

洛谷P1352 没有上司的舞会(树形DP水题)

题目描述 某大学有N个职员,编号为1~N.他们之间有从属关系,也就是说他们的关系就像一棵以校长为根的树,父结点就是子结点的直接上司.现在有个周年庆宴会,宴会每邀请来一个职员都会增加一定的快乐指数Ri,但是呢,如果某个职员的上司来参加舞会了,那么这个职员就无论如何也不肯来参加舞会了.所以,请你编程计算,邀请哪些职员可以使快乐指数最大,求最大的快乐指数. 输入输出格式 输入格式: 第一行一个整数N.(1<=N<=6000) 接下来N行,第i+1行表示i号职员的快乐指数Ri.(-128<=Ri

HDU-2196 Computer (树形DP)

最近在看树形DP,这题应该是树形DP的经典题了,写完以后还是有点感觉的.之后看了discuss可以用树分治来做,以后再试一试. 题目大意 找到带权树上离每个点的最远点.︿( ̄︶ ̄)︿ 题解: 对于每一个点的最远点,就是以这个点为根到所有叶子节点的最长距离.但是如果确定根的话,除了根节点外,只能找到每个节点(度数-1)个子树的最大值,剩下一个子树是该节点当前的父亲节点. 所以当前节点的最远点在当前节点子树的所有叶子节点以及父亲节点的最远点上(当父亲节点的最远点不在当前节点的子树上时), 如果父亲节

【BZOJ-2435】道路修建 (树形DP?)DFS

2435: [Noi2011]道路修建 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 3115  Solved: 1002[Submit][Status][Discuss] Description 在 W 星球上有 n 个国家.为了各自国家的经济发展,他们决定在各个国家之间建设双向道路使得国家之间连通.但是每个国家的国王都很吝啬,他们只愿意修建恰好 n – 1条双向道路. 每条道路的修建都要付出一定的费用, 这个费用等于道路长度乘以道路两端的国家

选课(洛谷_2014)——树形dp

我是来复习一下树形dp的 这题,需要了解--左儿子右兄弟--也就是说,这是一个多叉树转二叉树的方法,儿子位置不变,兄弟的位置变成右儿子 然后就和二叉苹果树差不多了. #include<iostream> #include<cstdio> #define max(a,b) a>b?a:b using namespace std; inline int read(){ int t=1,num=0;char c=getchar(); while(c>'9'||c<'0'