题目大意:
  给你一颗$n(n\le5000)$个点的树,选3个点使得它们两两距离相等,问共有几种选法。

思路:
  首先我们不难发现一个性质:对于每3个符合条件的点,我们总能找到一个点使得这个点到那3个点距离相等。
  我们不妨称之为“中转点”。
  显然答案就是对于每个中转点,不同子树中到这个点距离相等的三元点对的数量。
  我们可以先枚举每个点作为中转点的情况。
  暴力求出以这个点的每个子结点为根的子树,不同深度的结点的数量(显然深度就是到这个中转点的距离)。
  我们可以用calc[i][j]表示对于当前中转点,来自j个不同子树的深度为i的结点共有多少种不同的组合。
  转移方程为calc[i][j]+=calc[i][j-1]*cnt[i]。

 #include<cstdio>
#include<cctype>
#include<vector>
#include<cstring>
typedef long long int64;
inline int getint() {
register char ch;
while(!isdigit(ch=getchar()));
register int x=ch^'';
while(isdigit(ch=getchar())) x=(((x<<)+x)<<)+(ch^'');
return x;
}
const int N=;
std::vector<int> e[N];
inline void add_edge(const int &u,const int &v) {
e[u].push_back(v);
e[v].push_back(u);
}
int n,cnt[N];
int64 calc[N][];
void dfs(const int &x,const int &par,const int &dep) {
cnt[dep]++;
for(unsigned i=;i<e[x].size();i++) {
const int &y=e[x][i];
if(y==par) continue;
dfs(y,x,dep+);
}
}
int main() {
n=getint();
for(register int i=;i<n;i++) {
add_edge(getint(),getint());
}
int64 ans=;
for(register int x=;x<=n;x++) {
memset(calc,,sizeof calc);
for(register int i=;i<=n;i++) calc[i][]=;
for(register unsigned i=;i<e[x].size();i++) {
memset(cnt,,sizeof cnt);
const int &y=e[x][i];
dfs(y,x,);
for(register int j=;j;j--) {
for(register int i=;i<=n;i++) {
calc[i][j]+=calc[i][j-]*cnt[i];
}
}
}
for(register int i=;i<=n;i++) {
ans+=calc[i][];
}
}
printf("%lld\n",ans);
return ;
}   现在考虑当$n\le10^5$的情况。

  考虑$n\le10^5$的情况。
  $f[i][j]$标示以$i$为根的子树中,与$i$距离为$j$的点数。$g[i][j]$标示以$i$为根的子树中,与$i$距离为$j$的点对数。则不难想到一种$O(n^2)$的转移:
  $$
  \begin{align*}
  &g[x][i-1]+=g[y][i]\\
  &g[x][i+1]+=f[x][i+1]\times f[y][i]\\
  &f[x][i+1]+=f[y][i]
  \end{align*}
  $$
  ​边界为$f[x][0]=1$。
  考虑优化这个转移,不难发现,若$y$是$x$枚举到的第一个子结点,则转移时只进行第一、第三个转移。因此我们可以考虑通过指针来实现,免去转移的过程。
  将原树进行长链剖分,对于重边直接修改指针,对于轻边暴力转移,可以证明这样是$O(n)$的。

 #include<list>
#include<cstdio>
#include<cctype>
typedef long long int64;
inline int getint() {
register char ch;
while(!isdigit(ch=getchar()));
register int x=ch^'';
while(isdigit(ch=getchar())) x=(((x<<)+x)<<)+(ch^'');
return x;
}
const int N=;
std::list<int> e[N];
int dep[N],bot[N];
int64 mem[N*],ans,*f[N],*g[N],*ptr=mem;
inline void add_edge(const int &u,const int &v) {
e[u].push_back(v);
e[v].push_back(u);
}
void dfs(const int &x,const int &par) {
dep[bot[x]=x]=dep[par]+;
for(std::list<int>::iterator i=e[x].begin();i!=e[x].end();i++) {
const int &y=*i;
if(y==par) continue;
dfs(y,x);
if(dep[bot[y]]>dep[bot[x]]) bot[x]=bot[y];
}
for(register std::list<int>::iterator i=e[x].begin();i!=e[x].end();i++) {
const int &y=*i;
if(y==par||(bot[y]==bot[x]&&x!=)) continue;
f[bot[y]]=ptr+=dep[bot[y]]-dep[x]+;
g[bot[y]]=++ptr;
ptr+=(dep[bot[y]]-dep[x])*+;
}
}
void dp(const int &x,const int &par) {
for(std::list<int>::iterator i=e[x].begin();i!=e[x].end();i++) {
const int &y=*i;
if(y==par) continue;
dp(y,x);
if(bot[y]==bot[x]) {
f[x]=f[y]-;
g[x]=g[y]+;
}
}
ans+=g[x][];
f[x][]=;
for(register std::list<int>::iterator i=e[x].begin();i!=e[x].end();i++) {
const int &y=*i;
if(y==par||bot[y]==bot[x]) continue;
for(register int i=;i<=dep[bot[y]]-dep[x];i++) {
ans+=f[x][i-]*g[y][i]+g[x][i+]*f[y][i];
}
for(register int i=;i<=dep[bot[y]]-dep[x];i++) {
g[x][i-]+=g[y][i];
g[x][i+]+=f[x][i+]*f[y][i];
f[x][i+]+=f[y][i];
}
}
}
int main() {
const int n=getint();
for(register int i=;i<n;i++) {
add_edge(getint(),getint());
}
dfs(,);
dp(,);
printf("%lld\n",ans);
return ;
}

[POI2014]Hotel的更多相关文章

  1. BZOJ3522: [Poi2014]Hotel

    3522: [Poi2014]Hotel Time Limit: 20 Sec  Memory Limit: 128 MBSubmit: 195  Solved: 85[Submit][Status] ...

  2. 3522: [Poi2014]Hotel( 树形dp )

    枚举中点x( 即选出的三个点 a , b , c 满足 dist( x , a ) = dist( x , b ) = dist( x , c ) ) , 然后以 x 为 root 做 dfs , 显 ...

  3. 3522: [Poi2014]Hotel

    3522: [Poi2014]Hotel Time Limit: 20 Sec  Memory Limit: 128 MBSubmit: 253  Solved: 117[Submit][Status ...

  4. 【刷题】BZOJ 4543 [POI2014]Hotel加强版

    Description 同OJ3522 数据范围:n<=100000 Solution dp的设计见[刷题]BZOJ 3522 [Poi2014]Hotel 然后发现dp的第二维与深度有关,于是 ...

  5. 4543: [POI2014]Hotel加强版

    4543: [POI2014]Hotel加强版 链接 分析: f[u][i]表示子树u内,距离u为i的点的个数,g[u][i]表示在子树u内,已经选了两个深度一样的点,还需要在距离u为i的一个点作为第 ...

  6. BZOJ4543 POI2014 Hotel加强版 【长链剖分】【DP】*

    BZOJ4543 POI2014 Hotel加强版 Description 同OJ3522 数据范围:n<=100000 Sample Input 7 1 2 5 7 2 5 2 3 5 6 4 ...

  7. 【BZOJ4543】[POI2014]Hotel加强版 长链剖分+DP

    [BZOJ4543][POI2014]Hotel加强版 Description 同OJ3522数据范围:n<=100000 Sample Input 7 1 2 5 7 2 5 2 3 5 6 ...

  8. 【BZOJ3522】[Poi2014]Hotel 树形DP

    [BZOJ3522][Poi2014]Hotel Description 有一个树形结构的宾馆,n个房间,n-1条无向边,每条边的长度相同,任意两个房间可以相互到达.吉丽要给他的三个妹子各开(一个)房 ...

  9. bzoj4543[POI2014]Hotel

    题目链接 bzoj4543 [POI2014]Hotel 题解 这不是裸地点分嘛 ,我真傻,真的 n^2 这不是是sb题,~滑稽 ~ 枚举点转换为无根树,暴力子树中点的深度 计数转移 令a b c d ...

  10. bzoj4543 [POI2014]Hotel加强版 长链剖分+树形DP

    题目传送门 https://lydsy.com/JudgeOnline/problem.php?id=4543 题解 这道题的弱化版 bzoj3522 [POI2014]Hotel 的做法有好几种吧. ...

随机推荐

  1. js中的Map对象的简单示例

    es6提供一个对象Map, 其功能类似于java中的Map, 下面是java中的Map和js中的Map的简单对比: js中的Map.set()相当于java中的Map.put(), js中的Map.s ...

  2. 毕业答辩的PPT攻略

    关于内容: 1.一般概括性内容:课题标题.答辩人.课题执行时间.课题指导教师.课题的归属.致谢等.  2.课题研究内容:研究目的.方案设计(流程图).运行过程.研究结果.创新性.应用价值.有关课题延续 ...

  3. windows下maven打包eclipse工程

    打包过程中,可能出现的2个问题: ①.[WARNING] File encoding has not been set, using platform encoding GBK, i.e. build ...

  4. php多虚拟主机配置

    一.配置httpd.conf# Virtual hosts#Include conf/extra/httpd-vhosts.conf       //取消这一行的# 二.配置httpd-vhosts. ...

  5. Ajax的Result工具类

    ResultUtil.java package cn.qlq.util; import java.io.Serializable; public class ResultUtil<T> i ...

  6. AtCoder Regular Contest 092 C D E F

    C - 2D Plane 2N Points 题意 二维平面上有\(N\)个红点,\(N\)个蓝点,一个红点和一个蓝点能配成一对当且仅当\(x_r<x_b\)且\(y_r<y_b\). 问 ...

  7. YSlow安装兼容的环境版本

    YSlow:网站性能评分工具 1.安装 Firefox 282.安装 Firebug1.2.83.安装 YSlow3.1.8.1

  8. CDN缓存(转载)

    CDN缓存那些事(转载) 原文地址:http://bbs.qcloud.com/forum.php?mod=viewthread&tid=3775 注:原文全文复制,仅仅作为自己下次学习备份, ...

  9. NAT+穿洞基础知识梳理

    参考:https://www.cnblogs.com/shilxfly/p/6589255.html https://blog.csdn.net/phoenix06/article/details/7 ...

  10. SyntaxError: Non-ASCII character '\xe7' in file 错误的解决方法

    在代码开头写下面的定义即可 #encoding:utf-8