CDOJ 1284 苦恼的郭大侠 map启发式合并

苦恼的郭大侠

题目连接:

http://acm.uestc.edu.cn/#/problem/show/1284

Description

花开雷霆崖,血染伊吕波。

公元1772年。

郭大侠终于照着天行廖的叮嘱,摆出了阵型,准备带着部队与天行廖相逢于雷霆崖。

但郭大侠实在是没有把握,这个阵型是真的如天行廖所言,所向披靡,于是准备在于天行廖相逢前再确认一遍。

按照天行廖的叮嘱说,这个阵型得满足以下两个要求才能发挥最大威力:

1.这个阵型是一颗树,即n个点,n-1条边,任意两点之间都能互相到达。

2.这个阵型满足好朋友的对数大于n对,好朋友即满足P(u,v)=0,P(u,v)表示从u点到v点的简单路径上点编号的异或和。注意P(u,v)和P(v,u)视作一样,只计数一次。

郭大侠的士兵的的确确摆出了一颗树,但是点数太多了,很难统计好朋友的对数。

这可怎么办?

现在郭大侠找到了你,希望你能帮助憔悴的郭大侠解决这个问题,希望你能够数出这棵树上究竟有多少对好朋友。

Input

第一行n,表示点的数量,(1<=n<=100000)

接下来n-1行,每行两个整数u,v,表示点u与点v之间连有一条边(1<=u,v<=n)

保证是一棵树

Output

输出这棵树上究竟有多少对好朋友。

Sample Input

17
9 8
9 11
9 13
9 15
9 16
11 10
13 12
15 14
16 17
8 1
1 5
5 4
4 6
6 7
7 2
2 3

Sample Output

18

Hint

题意

题解:

map启发式合并就好了

对于每个点暴力统计答案就好了

代码

#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e6+7;
vector<int> E[maxn];
map<int,int> H[maxn];
int pre[maxn];
long long ans = 0;
void uni(int x,int y)
{
    if(H[x].size()<H[y].size())
        swap(H[x],H[y]);
    map<int,int>::iterator it;
    while(H[y].size())
    {
        it=H[y].begin();
        H[x][it->first]+=it->second;
        H[y].erase(it);
    }
}
void dfs(int x,int fa,int val)
{
    H[x][val]++;
    for(int i=0;i<E[x].size();i++)
    {
        int v = E[x][i];
        if(v == fa)continue;
        dfs(v,x,val^v);
        for(auto a:H[v])
        {
            int t = a.first^x;
            if(H[x].count(t))
                ans+=1ll*H[x][t]*a.second;
        }
        uni(x,v);
    }
}
int main()
{
    int n;
    scanf("%d",&n);
    for(int i=1;i<n;i++)
    {
        int x,y;scanf("%d%d",&x,&y);
        E[x].push_back(y);
        E[y].push_back(x);
    }
    dfs(1,0,1);
    cout<<ans<<endl;
}
    原文作者:qscqesze
    原文地址: https://www.cnblogs.com/qscqesze/p/5261616.html
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞