Problem E Similarity of Subtrees

题目

Problem E Similarity of Subtrees
Input: Standard Input Time Limit: See AtCoder
Define the depth of a node in a rooted tree by applying the following rules recursively:
• The depth of a root node is 0. • The depths of child nodes whose parents are with depth d are d + 1.
Let S(T,d) be the number of nodes of T with depth d. Two rooted trees T and T′ are similar if and only if S(T,d) equals S(T′,d) for all non-negative integer d.
You are given a rooted tree T with N nodes. The nodes of T are numbered from 1 to N. Node 1 is the root node of T. Let Ti be the rooted subtree of T whose root is node i. Your task is to write a program which calculates the number of pairs (i,j) such that Ti and Tj are similar and i < j.
Input
The input consists of a single test case.
N a1 b1 … aN−1 bN−1
The first line contains an integer N (1 ≤ N ≤ 100,000), which is the number of nodes in a tree. The following N −1 lines give information of branches: the i-th line of them contains ai and bi, which indicates that a node ai is a parent of a node bi. (1 ≤ ai,bi ≤ N, ai ̸= bi) The root node is numbered by 1. It is guaranteed that a given graph is a rooted tree, i.e. there is exactly one parent for each node except the node 1, and the graph is connected.
Output
Print the number of the pairs (x,y) of the nodes such that the subtree with the root x and the subtree with the root y are similar and x < y.
14
Sample Input 1
5 1 2 1 3 1 4 1 5
Output for the Sample Input 1
6
Sample Input 2
6 1 2 2 3 3 4 1 5 5 6
Output for the Sample Input 2
2
Sample Input 3
13 1 2 1 3 2 4 2 5 3 6 3 7 4 8 4 9 6 10 7 11 8 12 11 13
15
Output for the Sample Input 3
14

题目分析

这道题肯定是使用dfs从叶子节点向根推,其实就是递归的思想,但是相当于对于每个节点求一次值,然后对于这个值进行hash,这样就可以判断相似的数究竟有多少,然后迭代器跑一边求值即可。

#include <map>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int maxn = 1e5+100;
const int mod = 1e9+7;
typedef unsigned long long ULL;

ULL pri;
int head[maxn], tot;
map <ULL, int> M;

struct Edge{
    int to, next;
}e[maxn];

void addedge(int from, int to){
    e[tot].to = to;
    e[tot].next = head[from];
    head[from] = tot++;
}

ULL dfs(int u){
    ULL ans = 1;
    for(int i = head[u]; i != -1; i = e[i].next){
        ans += dfs(e[i].to)*pri;
    }
    M[ans]++;
    return ans;
}

void init(){
    tot = 0;
    M.clear();
    memset(head, -1, sizeof(head));
}

int main(){
    pri = mod;
    int n;
    while(scanf("%d", &n) != EOF){
        init();
        int from, to;
        for(int i = 1; i < n; i++){
            scanf("%d%d", &from, &to);
            addedge(from, to);
        }
        dfs(1);
        ULL ans = 0;
        for(map <ULL,int>::iterator it = M.begin(); it != M.end(); it++){
            ULL cnt = it->second;
            ans += cnt*(cnt-1)/2;
        }
        cout << ans << endl;
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值