Codeforces 506D:Mr. Kitayuta's Colorful Graph 并查集

D. Mr. Kitayuta's Colorful Graph
time limit per test
4 seconds
memory limit per test
256 megabytes
input
standard input
output
standard output

Mr. Kitayuta has just bought an undirected graph with n vertices and m edges. The vertices of the graph are numbered from 1 to n. Each edge, namely edge i, has a color ci, connecting vertex ai and bi.

Mr. Kitayuta wants you to process the following q queries.

In the i-th query, he gives you two integers - ui and vi.

Find the number of the colors that satisfy the following condition: the edges of that color connect vertex ui and vertex vi directly or indirectly.

Input

The first line of the input contains space-separated two integers - n and m(2 ≤ n ≤ 105, 1 ≤ m ≤ 105), denoting the number of the vertices and the number of the edges, respectively.

The next m lines contain space-separated three integers - aibi(1 ≤ ai < bi ≤ n) and ci(1 ≤ ci ≤ m). Note that there can be multiple edges between two vertices. However, there are no multiple edges of the same color between two vertices, that is, ifi ≠ j, (ai, bi, ci) ≠ (aj, bj, cj).

The next line contains a integer- q(1 ≤ q ≤ 105), denoting the number of the queries.

Then follows q lines, containing space-separated two integers - ui and vi(1 ≤ ui, vi ≤ n). It is guaranteed that ui ≠ vi.

Output

For each query, print the answer in a separate line.

Sample test(s)
input
4 5
1 2 1
1 2 2
2 3 1
2 3 3
2 4 3
3
1 2
3 4
1 4
output
2
1
0
input
5 7
1 5 1
2 5 1
3 5 1
4 5 1
1 2 2
2 3 2
3 4 2
5
1 5
5 1
2 5
1 5
1 4
output
1
1
1
1
2
Note

Let's consider the first sample.

The figure above shows the first sample.
  • Vertex 1 and vertex 2 are connected by color 1 and 2.
  • Vertex 3 and vertex 4 are connected by color 3.
  • Vertex 1 and vertex 4 are not connected by any single color.

题意是给出了通过不同颜色的边连接的一些点,有Q个查询,查询两个点可以用多少种不同颜色的边连接起来。

如果是一个颜色的边,然后Q个询问,询问两个点是否被连接,可以离线并查集搞。现在是m个颜色的边,那就一个一个颜色并查集搞。

但是,这里还是有问题,就是如何输出结果,这里也学习到了新姿势。就是如果这个颜色的点很多的话,那就遍历Q个查询,记录结果。如果这个颜色的点很少的话,那就O(n^2)记录这些颜色的点。

代码:

#pragma warning(disable:4996)  
#include <iostream>
#include <algorithm>
#include <cstring>
#include <vector>
#include <string>
#include <cstdio>
#include <cmath>
#include <queue>
#include <stack>
#include <set>
#include <map>
using namespace std;

#define INF 0x3fffffff
typedef long long ll;

const int mod = 1e9 + 7;
const int maxn = 1e5 + 5;

int n, m, q;
vector<int>po;
vector<pair<int, int>>edg[maxn];
map<pair<int, int>, int>res;
int fa[maxn], ans[maxn], qu[maxn], qv[maxn], cor[maxn];

int find(int x)
{
	return x == fa[x] ? x : fa[x] = find(fa[x]);
}

void merge(int x, int y)
{
	fa[x] = y;
}

void input()
{
	int i, s, e, cor;
	scanf("%d%d", &n, &m);

	for (i = 1; i <= m; i++)
	{
		scanf("%d%d%d", &s, &e, &cor);
		edg[cor].push_back(make_pair(s, e));
	}

	scanf("%d", &q);
	for (i = 1; i <= q; i++)
	{
		scanf("%d%d", &qu[i], &qv[i]);
	}
}

void solve()
{
	int i, j, k;
	for (i = 1; i <= m; i++)
	{	
		int sz = edg[i].size();
		if (sz == 0)continue;
		po.clear();
		for (j = 0; j<sz; j++)
		{
			po.push_back(edg[i][j].first);
			po.push_back(edg[i][j].second);
		}
		sort(po.begin(), po.end());
		po.erase(unique(po.begin(), po.end()), po.end());

		int po_sz = po.size();
		for (j = 0; j<po_sz; j++)
		{
			int poin = po[j];
			cor[poin] = i;
			fa[poin] = poin;
		}
		for (j = 0; j<sz; j++)
		{
			int u = edg[i][j].first;
			int v = edg[i][j].second;
			if (find(u) != find(v))
			{
				merge(find(u), find(v));
			}
		}
		if ((ll)po_sz*(ll)po_sz > n)
		{
			for (j = 1; j <= q; j++)
			{
				if (cor[qu[j]] == i&&cor[qv[j]] == i)
				{
					if (find(qu[j]) == find(qv[j]))
					{
						ans[j]++;
					}
				}
			}
		}
		else
		{
			for (j = 0; j < po_sz; j++)
			{
				for (k = j + 1; k < po_sz; k++)
				{
					if (find(po[j]) == find(po[k]))
					{
						res[make_pair(po[k], po[j])]++;
						res[make_pair(po[j], po[k])]++;
					}
				}
			}
		}
	}

	for (i = 1; i <= q; i++)
	{
		printf("%d\n", ans[i] + res[make_pair(qu[i], qv[i])]);
	}
}

int main()
{
	//freopen("i.txt","r",stdin);
	//freopen("o.txt","w",stdout);
	
	input();
	solve();
	
	//system("pause");
	return 0;
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值