树的重心,树形$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. 应用Xml.Linq读xml文件

    c#提供了System.Xml.Linq操作xml文件,非常方便,本文主要介绍如何应用System.Xml.Linq读取xml文件. xml文本 <?xml version="1.0& ...

  2. Flume入门——Selector、Chanel等

    1.selector (http://blog.csdn.net/looklook5/article/details/40430965) (http://blog.csdn.net/xiao_jun_ ...

  3. dp优化-四边形不等式(模板题:合并石子)

    学习博客:https://blog.csdn.net/noiau/article/details/72514812 看了好久,这里整理一下证明 方程形式:dp(i,j)=min(dp(i,k)+dp( ...

  4. 【洛谷 P4008】 [NOI2003]文本编辑器 (Splay)

    题目链接 \(Splay\)先练到这吧(好像还有道毒瘤的维护数列诶,算了吧) 记录下光标的编号,维护就是\(Splay\)基操了. 另外数据有坑,数据是\(Windows\)下生成了,回车是'\n\r ...

  5. [bzoj4567][Scoi2016]背单词-Trie+贪心+模型转化

    Brief Description 给你N个互不相同的字符串,记\(S_i\)为第i个字符串,现在要求你指定N个串的出现顺序,我们用\(V_i\)表示第i个字符串是第几个出现的,则V为1到N的一个排列 ...

  6. 复现VGG19训练自定义图像分类

    1.复现VGG训练自定义图像分类,成功了哈哈. 需要代码工程可联系博主qq号,在左边连接可找到. 核心代码: # coding:utf-8 import tensorflow as tf import ...

  7. javascript 事件知识集锦

    1.事件委托极其应用 转载的链接:  http://www.webhek.com/event-delegate/#comments 2. 解析javascript事件机制 转载链接:    http: ...

  8. ADC 計算時,階數的選擇

    reference : ADC 階數的計算

  9. tornado当用户输入的URL无效时转入设定的页面

    今天做web的测验..坑爹的要用tornado...作为一个比较新的用的人还不多的东东...查资料好麻烦.. 下面是当用户输入非法 url时, 显示一个自定义 404 页面提示用户,其访问的页面不存在 ...

  10. 网站服务器压力Web性能测试(3):http_load:测试web服务器的吞吐量与负载

    1.http_load是国外一个博主写的一个基于Linux的性能测工具,小巧轻便,解压缩后不到100k,下载安装方法: wget https://acme.com/software/http_load ...