魏佬怒嘲我只会做给定一棵树,输出有多少个点这种问题

不过我连这个也不会做

还算一道不错的树上数数题目

但是我一直不会数数

求树上所有的三元组\((u,v,t)\),满足\(dis(u,v)=dis(u,t)=dis(v,t)\)的个数

感觉好神仙啊,一眼不会的感觉

之后试着挖掘一下性质,发现只要我们需要找一个点\(x\)使得这三个点到\(dis(x,u)=dis(x,v)=dis(x,t)\)好像就可以了

吗?

显然不行啊

就比如这一棵树,确实这里是有\(dis(x,u)=dis(v,x)=dis(t,x)=2\),但是\(dis(u,v)=2\),而\(dis(t,u)=4\),这显然并不对

所以这个性质还得有一个限制条件,就是\(x=LCA(u,v)\)

我们把问题分成两步

  1. \(u,v,t\)在一棵子树里

  2. \(u,v\)在一棵子树里,\(t\)在子树外

有没有\(up\ and\ down\)的意味了,在\(up\)里我们就能统计第一种情况的答案了

我们定义\(dp[x][j]\)表示在\(x\)的子树内部有多少个点到达\(x\)的距离为\(j\),显然这个非常好转移

\(f[x][j]\)表示在\(x\)的子树内部,有多少对\((u,v)\)满足\(dis(u,v)=j\),且\(LCA(u,v)=x\),这个在合并子树的时候也可顺边求出来

而合并子树的时候,我们每次合并的时候就可以统计第一种答案了,由于\(u\)和\(v\)显然不能来自于同一棵子树内部,所以合并的时候直接拿这个去乘上之前的\(f[x][j]\)就好了

第二种情况,我们直接\(down\)下来,首先还是先\(down\)一下\(dp\)数组,求出子树外部到\(x\)距离为\(j\)的点有多少个,这些点就可以作为\(t\),之后乘上\((u,v)\)点对的数量,我们就可以把答案合并出来了

代码

#include<iostream>
#include<cstring>
#include<cstdio>
#define re register
#define maxn 5001
#define LL long long
#define max(a,b) ((a)>(b)?(a):(b))
struct E
{
short v,nxt;
}e[maxn<<1];
short deep[maxn],head[maxn],md[maxn];
int dp[maxn][maxn],f[maxn][maxn];
int n,num;
LL ans;
inline void add_edge(int x,int y)
{
e[++num].v=y;
e[num].nxt=head[x];
head[x]=num;
}
inline int read()
{
char c=getchar();
int x=0;
while(c<'0'||c>'9') c=getchar();
while(c>='0'&&c<='9')
x=(x<<3)+(x<<1)+c-48,c=getchar();
return x;
}
inline LL merge(LL x,LL y)
{
return (x-1)*x/2*y;
}
void dfs(int x)
{
dp[x][0]++;
for(re int i=head[x];i;i=e[i].nxt)
if(!deep[e[i].v])
{
md[e[i].v]=deep[e[i].v]=deep[x]+1;
dfs(e[i].v);
md[x]=max(md[x],md[e[i].v]);
for(re int j=1;j<=md[x];j++)
ans+=f[x][j]*dp[e[i].v][j-1],f[x][j]+=dp[x][j]*dp[e[i].v][j-1],dp[x][j]+=dp[e[i].v][j-1];
}
}
void Redfs(int x)
{
for(re int i=head[x];i;i=e[i].nxt)
if(deep[e[i].v]>deep[x])
{
for(re int j=n;j;j--)
if(j>=2) ans+=(dp[x][j-1]-dp[e[i].v][j-2])*f[e[i].v][j],dp[e[i].v][j]+=dp[x][j-1]-dp[e[i].v][j-2];
else ans+=dp[x][j-1]*f[e[i].v][j],dp[e[i].v][j]+=dp[x][j-1];
Redfs(e[i].v);
}
}
int main()
{
n=read();
int x,y;
for(re int i=1;i<n;i++)
x=read(),y=read(),add_edge(x,y),add_edge(y,x);
md[1]=deep[1]=1;
dfs(1);
Redfs(1);
std::cout<<ans;
return 0;
}

最新文章

  1. SQL Queries from Transactional Plugin Pipeline
  2. Genymotion出现virtualbox cannot start the virtual device错误
  3. linux numfmt 命令--转换数字
  4. [转] EJB 3和Spring技术体系比较
  5. RFID 读写器 Reader Writer Cloner
  6. Spring资源访问
  7. linux上安装mysql
  8. 驱动程序环境搭配(VS2010 + WDK + VirtualDDK + VMware)good
  9. php 添加 redis 扩展模块
  10. WCF中队列服务详解
  11. htt p第一章概述
  12. c语言基础学习07
  13. ubuntu18.04搭建 kubernetes(k8s)集群
  14. PostgreSql 查询表结构和说明
  15. Python字符串与格式化的一点用法
  16. Docker环境下的Mysql8 实现主从数据库数据同步方案
  17. Netty 线程模型
  18. JDK 1.8 sun.misc.Unsafe类CAS底层实现
  19. BZOJ4910 : [Sdoi2017] 苹果树
  20. BZOJ4025 二分图(线段树分治+并查集)

热门文章

  1. EF面试题
  2. 腾讯企业邮箱报错 &quot;smtp.exmail.qq.com&quot;port 465, isSSL false
  3. GString惰性求值
  4. jquery获取哪一个下拉框被选中
  5. csharp: Gets a files formatted size.
  6. 4.5&amp;4.7联考题解
  7. mybatis三种传值方式
  8. html5 区块与内联div 与span html块级元素
  9. css权威指南读书笔记-第10章浮动和定位
  10. Angular入门教程二