树的重心,树形$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的更多相关文章

  1. hdu 4912 Paths on the tree(树链拆分+贪婪)

    题目链接:hdu 4912 Paths on the tree 题目大意:给定一棵树,和若干个通道.要求尽量选出多的通道,而且两两通道不想交. 解题思路:用树链剖分求LCA,然后依据通道两端节点的LC ...

  2. (hdu)5423 Rikka with Tree (dfs)

    题目链接:http://acm.split.hdu.edu.cn/showproblem.php?pid=5423 Problem Description As we know, Rikka is p ...

  3. 【hdu 6161】Big binary tree(二叉树、dp)

    多校9 1001 hdu 6161 Big binary tree 题意 有一个完全二叉树.编号i的点值是i,操作1是修改一个点的值为x,操作2是查询经过点u的所有路径的路径和最大值.10^5个点,1 ...

  4. 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 ...

  5. hdu 5534 (完全背包) Partial Tree

    题目:这里 题意: 感觉并不能表达清楚题意,所以 Problem Description In mathematics, and more specifically in graph theory, ...

  6. 【HDU 4408】Minimum Spanning Tree(最小生成树计数)

    Problem Description XXX is very interested in algorithm. After learning the Prim algorithm and Krusk ...

  7. 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 ...

  8. 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 ...

  9. HDU - 5156 Harry and Christmas tree

    题目链接 : http://acm.hdu.edu.cn/showproblem.php?pid=5156 题意 : 给一颗编号为1-n的以1为根的树, 已知有m个颜色的礼物分布在某些节点上(同一节点 ...

随机推荐

  1. homebrew常见用法

    1. 安装 Homebrew是mac下安装软件的好帮手, 是使用 ruby 写的,采用 github 来存放信息库,很方便吧. Ruby 已经内置,最好装上 Xcode,因为可能需要一些编译包.然后在 ...

  2. IE8动态创建CSS

    IE8动态创建CSS 最近在项目中用到在页面中动态创建CSS方法,记录一下方便以后查看 一. 在IE下动态创建(网上收集3种方法,最后一个方法未测试成功,具体不知道什么原因) 第一种(此方法很麻烦,需 ...

  3. 图论:最短路-Dijkstra

    Dijkstra+堆优化具有稳定的时间复杂度,在一些数据范围要求比较严格(准确来说是图比较苛刻)的时候能够保证稳定的时间复杂度 但是Dijkstra不能够解决负边权的问题,所以在使用的时候一定要仔细读 ...

  4. redis的安装和常用命令

    一.redis的安装 1.windows安装redis 下载地址:https://github.com/MSOpenTech/redis/releases. Redis 支持 32 位和 64 位.这 ...

  5. NDK---使用,开发步骤

    使用NDk的场景: 1.某些方法,是使用C,C++本地代码实现的,然后,我想在Java中调用这些方法.这个时候,就需要使用到JNI技术. 应用NDK的时候,分两个部分,Java部分,JNI层部分,本地 ...

  6. nginx与php-fpm通讯方式

    nginx和php-fpm的通信方式有两种,一种是tcp socket的方式,一种是unix socke方式. tcp sockettcp socket的优点是可以跨服务器,当nginx和php-fp ...

  7. 计蒜客 Goldbach Miller_Rabin判别法(大素数判别法)

    题目链接:https://nanti.jisuanke.com/t/25985 题目: Description: Goldbach's conjecture is one of the oldest ...

  8. 24、redis中的sentinel的作用?

    redis中的sentinel的作用? Redis-Sentinel是Redis官方推荐的高可用性(HA)解决方案,当用Redis做Master-slave的高可用方案时,假如master宕机了,Re ...

  9. 【Python学习笔记】Coursera课程《Python Data Structures》 密歇根大学 Charles Severance——Week6 Tuple课堂笔记

    Coursera课程<Python Data Structures> 密歇根大学 Charles Severance Week6 Tuple 10 Tuples 10.1 Tuples A ...

  10. 网络设备之pci_device_id

    标准PCI设备都有一个配置寄存器,用来存储各种参数: /* pci设备配置寄存器 */ struct pci_device_id { /* 厂商id,设备id */ __u32 vendor, dev ...