HDU 4863 Centroid of a Tree
树的重心,树形$dp$,背包。
树的重心有两个充分必要条件:
$1$.某树有两个重心$a$,$b$ $<=>$ $a$与$b$相邻,断开$a$与$b$之间的边之后,两个联通分量内的点的个数相同。
$2$.某树有一个重心$a$ $<=>$ 以$a$为根的树,去掉a之后,剩下的联通分量,除去节点个数最多的联通分量后,剩余的联通分量节点个数之和大于等于最大的联通分量的节点个数。
因此,可以先计算出初始树的重心,分两种情况讨论。
如果有两个重心$a$,$b$,那么,我们需要计算出断开$a$,$b$之间的边,以$a$为根的树以及以$b$为根的树中包含$x$个节点的树有几种,然后枚举$x$两边相乘求和就是答案了。
如果只有一个重心$a$,这种情况比两个重心的复杂一点,需要计算以$a$为根的树有多少种满足充要条件$2$,先要计算出以$a$的儿子为根的树中包含$x$个节点的树有几种,然后再用背包去算一下反面的情况,总的方案减去反面的就是答案。
#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<vector>
#include<map>
#include<set>
#include<queue>
#include<stack>
#include<ctime>
#include<iostream>
using namespace std;
typedef long long LL;
const double pi=acos(-1.0);
void File()
{
freopen("D:\\in.txt","r",stdin);
freopen("D:\\out.txt","w",stdout);
}
template <class T>
inline void read(T &x)
{
char c = getchar();
x = ;
while(!isdigit(c)) c = getchar();
while(isdigit(c))
{
x = x * + c - '';
c = getchar();
}
} int T,n;
int mod=;
int dp[][];
int c[],mx[],k[],f[];
vector<int>tmp[],t[],zx; void init()
{
memset(dp,,sizeof dp);
memset(c,,sizeof c);
memset(mx,,sizeof mx);
memset(f,,sizeof f);
for(int i=;i<=n;i++) tmp[i].clear();
for(int i=;i<=n;i++) t[i].clear();
zx.clear();
} void D(int x)
{
f[x]=;
for(int i=;i<tmp[x].size();i++)
{
if(f[tmp[x][i]]) continue;
t[x].push_back(tmp[x][i]);
D(tmp[x][i]);
}
} void F(int x)
{
for(int i=;i<t[x].size();i++)
{
F(t[x][i]);
mx[x]=max(mx[x],c[t[x][i]]);
c[x]=c[x]+c[t[x][i]];
}
c[x]++;
} void G(int x)
{
f[x]=;
for(int i=;i<tmp[x].size();i++)
{
if(f[tmp[x][i]]) continue;
if(zx.size()==&&tmp[x][i]==zx[]) continue;
t[x].push_back(tmp[x][i]);
G(tmp[x][i]);
}
} void DP(int x)
{
dp[x][]=; int h[],g[];
memset(h,,sizeof h); memset(g,,sizeof g);
g[]=;
for(int i=;i<t[x].size();i++)
{
DP(t[x][i]);
for(int j=;j<=c[x]+c[t[x][i]];j++) h[j]=;
for(int p1=c[x];p1>=;p1--)
for(int p2=c[t[x][i]];p2>=;p2--)
h[p1+p2]=(h[p1+p2]+g[p1]*dp[t[x][i]][p2]%mod)%mod;
for(int j=;j<=c[x]+c[t[x][i]];j++) g[j]=h[j]; c[x]=c[x]+c[t[x][i]];
}
c[x]++;
for(int i=;i<=;i++) dp[x][i]=g[i-];
} int main()
{
scanf("%d",&T); int cas=;
while(T--)
{
scanf("%d",&n);
init();
for(int i=;i<=n-;i++)
{
int x,y; scanf("%d%d",&x,&y);
tmp[x].push_back(y);
tmp[y].push_back(x);
}
D(); F(); for(int i=;i<=n;i++) k[i]=max(mx[i],n-c[i]);
int mn=; for(int i=;i<=n;i++) mn=min(mn,k[i]);
for(int i=;i<=n;i++) if(k[i]==mn) zx.push_back(i); for(int i=;i<=n;i++) t[i].clear();
memset(f,,sizeof f);
G(zx[]); if(zx.size()==) G(zx[]); memset(c,,sizeof c);
DP(zx[]); if(zx.size()==) DP(zx[]); printf("Case %d: ",cas++); int ans=;
if(zx.size()==)
{
int h[],g[]; int fm=;
for(int i=;i<t[zx[]].size();i++)
{
memset(h,,sizeof h); memset(g,,sizeof g); g[]=;
int a=;
for(int j=;j<t[zx[]].size();j++)
{
if(i==j) continue;
for(int w=;w<=a+c[t[zx[]][j]];w++) h[w]=;
for(int p1=a;p1>=;p1--)
for(int p2=c[t[zx[]][j]];p2>=;p2--)
h[p1+p2]=(h[p1+p2]+g[p1]*dp[t[zx[]][j]][p2]%mod)%mod;
a=a+c[t[zx[]][j]];
for(int j=;j<=;j++) g[j]=h[j];
} for(int j=;j<=c[t[zx[]][i]];j++)
for(int w=;w<j;w++)
fm=(fm+dp[t[zx[]][i]][j]*g[w]%mod)%mod;
}
for(int i=;i<=n;i++) ans=(ans+dp[zx[]][i])%mod;
printf("%d\n",(ans-fm+mod)%mod); }
else
{
for(int i=;i<=;i++)
ans=(ans+dp[zx[]][i]*dp[zx[]][i]%mod)%mod;
printf("%d\n",ans);
} }
return ;
}
HDU 4863 Centroid of a Tree的更多相关文章
- hdu 4912 Paths on the tree(树链拆分+贪婪)
题目链接:hdu 4912 Paths on the tree 题目大意:给定一棵树,和若干个通道.要求尽量选出多的通道,而且两两通道不想交. 解题思路:用树链剖分求LCA,然后依据通道两端节点的LC ...
- (hdu)5423 Rikka with Tree (dfs)
题目链接:http://acm.split.hdu.edu.cn/showproblem.php?pid=5423 Problem Description As we know, Rikka is p ...
- 【hdu 6161】Big binary tree(二叉树、dp)
多校9 1001 hdu 6161 Big binary tree 题意 有一个完全二叉树.编号i的点值是i,操作1是修改一个点的值为x,操作2是查询经过点u的所有路径的路径和最大值.10^5个点,1 ...
- HDU 6191 Query on A Tree(可持久化Trie+DFS序)
Query on A Tree Time Limit: 20000/10000 MS (Java/Others) Memory Limit: 132768/132768 K (Java/Othe ...
- hdu 5534 (完全背包) Partial Tree
题目:这里 题意: 感觉并不能表达清楚题意,所以 Problem Description In mathematics, and more specifically in graph theory, ...
- 【HDU 4408】Minimum Spanning Tree(最小生成树计数)
Problem Description XXX is very interested in algorithm. After learning the Prim algorithm and Krusk ...
- Hdu.1325.Is It A Tree?(并查集)
Is It A Tree? Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others) To ...
- hdu 1325 Is It A Tree?
Is It A Tree? Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others) To ...
- HDU - 5156 Harry and Christmas tree
题目链接 : http://acm.hdu.edu.cn/showproblem.php?pid=5156 题意 : 给一颗编号为1-n的以1为根的树, 已知有m个颜色的礼物分布在某些节点上(同一节点 ...
随机推荐
- homebrew常见用法
1. 安装 Homebrew是mac下安装软件的好帮手, 是使用 ruby 写的,采用 github 来存放信息库,很方便吧. Ruby 已经内置,最好装上 Xcode,因为可能需要一些编译包.然后在 ...
- IE8动态创建CSS
IE8动态创建CSS 最近在项目中用到在页面中动态创建CSS方法,记录一下方便以后查看 一. 在IE下动态创建(网上收集3种方法,最后一个方法未测试成功,具体不知道什么原因) 第一种(此方法很麻烦,需 ...
- 图论:最短路-Dijkstra
Dijkstra+堆优化具有稳定的时间复杂度,在一些数据范围要求比较严格(准确来说是图比较苛刻)的时候能够保证稳定的时间复杂度 但是Dijkstra不能够解决负边权的问题,所以在使用的时候一定要仔细读 ...
- redis的安装和常用命令
一.redis的安装 1.windows安装redis 下载地址:https://github.com/MSOpenTech/redis/releases. Redis 支持 32 位和 64 位.这 ...
- NDK---使用,开发步骤
使用NDk的场景: 1.某些方法,是使用C,C++本地代码实现的,然后,我想在Java中调用这些方法.这个时候,就需要使用到JNI技术. 应用NDK的时候,分两个部分,Java部分,JNI层部分,本地 ...
- nginx与php-fpm通讯方式
nginx和php-fpm的通信方式有两种,一种是tcp socket的方式,一种是unix socke方式. tcp sockettcp socket的优点是可以跨服务器,当nginx和php-fp ...
- 计蒜客 Goldbach Miller_Rabin判别法(大素数判别法)
题目链接:https://nanti.jisuanke.com/t/25985 题目: Description: Goldbach's conjecture is one of the oldest ...
- 24、redis中的sentinel的作用?
redis中的sentinel的作用? Redis-Sentinel是Redis官方推荐的高可用性(HA)解决方案,当用Redis做Master-slave的高可用方案时,假如master宕机了,Re ...
- 【Python学习笔记】Coursera课程《Python Data Structures》 密歇根大学 Charles Severance——Week6 Tuple课堂笔记
Coursera课程<Python Data Structures> 密歇根大学 Charles Severance Week6 Tuple 10 Tuples 10.1 Tuples A ...
- 网络设备之pci_device_id
标准PCI设备都有一个配置寄存器,用来存储各种参数: /* pci设备配置寄存器 */ struct pci_device_id { /* 厂商id,设备id */ __u32 vendor, dev ...