【Bzoj3522】Hotel

4 篇文章 0 订阅
4 篇文章 0 订阅

题意

有一个树形结构,每条边的长度相同,任意两个节点可以相互到达。选3个点。两两距离相等。有多少种方案?


解析

满足条件的点对一定是“有一个中心点,三个点到中心点的距离相等,且三个点分别在不同子树中”这种情况。(因为如果在同一子树中会被重复统计)。
那么枚举中心点,然后遍历子树,统计答案。
令cnt[i]表示当前子树中深度为i的点有多少个。
f[i]表示当前点已经遍历过的子树中,深度为i的点有多少个。
g[i]表示当前点已经遍历过的子树中,两个点深度都为i的点对有多少个。
根据乘法原理ans += ∑(g[i] * cnt[i])。每次用f和cnt去更新g,用cnt去更新f。



#include <cstdio>
#include <cstring>
#include <algorithm>

#define Rep( i , _begin , _end ) for(int i=(_begin),i##_END=(_end);i<=(i##_END);i++)
#define For( i , _begin , _end ) for(int i=(_begin),i##_END=(_end);i!=(i##_END);i++)
#define Lop( i , _begin , _end ) for(int i=(_begin),i##_END=(_end);i>=(i##_END);i--)
#define Dnt( i , _begin , _end ) for(int i=(_begin),i##_END=(_end);i!=(i##_END);i--)

using std :: max;
using std :: min;

typedef long long LL;

const int maxx = 100000 + 25;

int n,m,x,y,z,num;
LL  ans;

int f[maxx],g[maxx],cnt[maxx],son[maxx];
int head[maxx],nxt[maxx],to[maxx];

void Ins(int x,int y){
    to[++num] = y;nxt[num] = head[x];head[x] = num;son[x] ++;
}

void Dfs(int x,int pre,int dpt){
    cnt[dpt] ++;
    for(int i=head[x];i;i=nxt[i])
        if(to[i] != pre)
            Dfs(to[i],x,dpt+1);
}

int main(){
    scanf("%d",&n);
    For( i , 1 , n ) scanf("%d%d",&x,&y),Ins(x,y),Ins(y,x);
    Rep( x , 1 , n ){
        if(son[x] < 3) continue;
        memset(f,0,sizeof(f));
        memset(g,0,sizeof(g));
        for(int i=head[x];i;i=nxt[i]){
            memset(cnt,0,sizeof(cnt));
            Dfs(to[i],x,1);
            Rep( k , 1 , n ){
                ans += (LL)cnt[k] * g[k];
                g[k] += f[k] * cnt[k];
                f[k] += cnt[k];
            }
        }
    }
    printf("%lld\n",ans);
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值