码迷,mamicode.com
首页 > 其他好文 > 详细

CDOJ 1284 郭大侠与苦恼 (map启发式合并) - xgtao -

时间:2016-08-01 22:45:36      阅读:188      评论:0      收藏:0      [点我收藏+]

标签:

题目链接

 

题目给出一个有N(<=100000)节点的树,找出"好朋友数"的对数,定义好朋友数对于(u,v)如果u->v简单路径上的所有点异或的和为0,那么(u,v)是一对好朋友,但是(u,v)和(v,u)是同一对。

 

从1号节点搜索下去,用p[v][x]表示从1号节点到达v的异或值为x的出现的个数,节点a到b的路径的的异或值为a^x1^x2^x3^x4..^u...^y1^y2^y3^y4^b,以u为公共祖先val[a] = a^x1^x2^x3^x4..^u,val[b] = u^y1^y2^y3^y4^b,所以a->b路径的异或值为val[a]^val[b]^u,那么如果路径的异或值等于零的话,val[a]^val[b]^u = 0,所以val[b]^u = val[a],将a的p一直向上合并给u的过程中,如果val[b]^u在p[u]里面出现过,那么说明存在有好朋友,ans += p[u][val[b]^u]*p[v][val[b]];

 

 

#include <cstdio>
#include <iostream>
#include <cstring>
#include <vector>
#include <map>
#include <algorithm>
using namespace std;
const int N = 100010;

int n;
long long ans;
map <int,int> p[N];
vector <int> edge[N];

void Union(int u,int v){
	if(p[u].size()<p[v].size())swap(p[u],p[v]);
	map<int,int>::iterator it;
	while(p[v].size()){
		it = p[v].begin();
		p[u][it->first] += it->second;
		p[v].erase(it);
	}
}

void dfs(int u,int fa,int x){
	p[u][x]++;
	for(int i = 0;i < edge[u].size();++i){
		int v = edge[u][i];
		if(v == fa)continue;
		dfs(v,u,x^v);
		map<int,int>::iterator it;
		for(it = p[v].begin();it != p[v].end();++it){
			int val = it->first^u;
			if(p[u].count(val))ans += p[u][val]*it->second;
		}
		Union(u,v);
	}
}

int main(){
	scanf("%d",&n);
	for(int i = 1;i < n;++i){
		int u,v;
		scanf("%d%d",&u,&v);
		edge[u].push_back(v);
		edge[v].push_back(u);
	}
	dfs(1,-1,1);
	cout<<ans<<endl;
	return 0;
}

  

CDOJ 1284 郭大侠与苦恼 (map启发式合并) - xgtao -

标签:

原文地址:http://www.cnblogs.com/xgtao984/p/5727329.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!