Chemical table_CodeForces1013D

题目

Innopolis University scientists continue to investigate the periodic table. There are n·m known elements and they form a periodic table: a rectangle with n rows and m columns. Each element can be described by its coordinates (r, c) (1 ≤ r ≤ n, 1 ≤ c ≤ m) in the table.

Recently scientists discovered that for every four different elements in this table that form a rectangle with sides parallel to the sides of the table, if they have samples of three of the four elements, they can produce a sample of the fourth element using nuclear fusion. So if we have elements in positions (r1, c1), (r1, c2), (r2, c1), where r1 ≠ r2 and c1 ≠ c2, then we can produce element (r2, c2).

Samples used in fusion are not wasted and can be used again in future fusions. Newly crafted elements also can be used in future fusions.

Innopolis University scientists already have samples of q elements. They want to obtain samples of all n·m elements. To achieve that, they will purchase some samples from other laboratories and then produce all remaining elements using an arbitrary number of nuclear fusions in some order. Help them to find the minimal number of elements they need to purchase.

Input

The first line contains three integers nmq (1 ≤ n, m ≤ 200 000; 0 ≤ q ≤ min(n·m, 200 000)), the chemical table dimensions and the number of elements scientists already have.

The following q lines contain two integers rici (1 ≤ ri ≤ n, 1 ≤ ci ≤ m), each describes an element that scientists already have. All elements in the input are different.

Output

Print the minimal number of elements to be purchased.

Examples

Input

2 2 3
1 2
2 2
2 1

Output

0

Input

1 5 3
1 3
1 1
1 5

Output

2

Input

4 3 6
1 2
1 3
2 2
2 3
3 1
3 3

Output

1

Note

For each example you have a picture which illustrates it.

The first picture for each example describes the initial set of element samples available. Black crosses represent elements available in the lab initially.

The second picture describes how remaining samples can be obtained. Red dashed circles denote elements that should be purchased from other labs (the optimal solution should minimize the number of red circles). Blue dashed circles are elements that can be produced with nuclear fusion. They are numbered in order in which they can be produced.

Test 1

We can use nuclear fusion and get the element from three other samples, so we don't need to purchase anything.

Test 2

We cannot use any nuclear fusion at all as there is only one row, so we have to purchase all missing elements.

Test 3

There are several possible solutions. One of them is illustrated below.

Note that after purchasing one element marked as red it's still not possible to immidiately produce the middle element in the bottom row (marked as 4). So we produce the element in the left-top corner first (marked as 1), and then use it in future fusions

题目大意

 给你一个n*m的矩阵,以及q个坐标

依次输入每个坐标

如果存在三个坐标分别在某一个矩形的三个角上,那么剩下的那一个角也会默认出现了坐标

比如

输入(1,3)  (2,1)  (2,2) 这三个坐标分别是矩形的三个顶点 ,那么矩形的另一个顶点(1,1)会自动覆盖 (就不需要手动覆盖了)

如果不存在这样的情况,就要手动覆盖整个坐标,从而使整个棋盘完全被覆盖

要求输出需要手动覆盖多少点

算法:并查集

int pri[maxn];
int find(int x)              				//找祖先并压缩路径 
{
    return pri[x]==x?x:pri[x]=find(pri[x]);
}
void join(int x,int y)                                                                                                    //判断x y是否连通,                                                                                            //如果已经连通,就不用管了 //如果不连通,就把它们所在的连通分支合并起,
{
    int fx=find(x),fy=find(y);
    if(fx!=fy) pri[fx]=fy;
}

代码

#include<iostream>
#define maxn 400100
using namespace std;
int pri[maxn];
int find(int x)              				//找祖先并压缩路径 
{
    return pri[x]==x?x:pri[x]=find(pri[x]);
}
void join(int x,int y)                                                                                                    //判断x y是否连通,                                                                                            //如果已经连通,就不用管了 //如果不连通,就把它们所在的连通分支合并起,
{
    int fx=find(x),fy=find(y);
    if(fx!=fy) pri[fx]=fy;
}
int main()
{
	int n,m,t; 
	cin>>n>>m>>t;
	for(int i=1;i<=n+m;i++)
		pri[i]=i; 						//初始化祖先为自己 
	while(t--)
	{
		int x,y;
		cin>>x>>y;
		join(x,y+n);		
	}
	int ans=0;
	for(int i=1;i<=n+m;i++)
		if(find(i)==i) ans++;
	cout<<ans-1;
	return 0;
}

 分析

 每次输入坐标,其实就是输入行和列(一共n行m列)

 每输入一次坐标,就把行和列join

比如(1.1) (3.1) (3.3)

首先把1行1列join  现在1行1列祖先都是1列 

然后把3行1列join  现在3行1列以及1行祖先都是1列 

然后把3行3列join  现在3行3列祖先都是3列 (3行之前的祖先是1列,join 把1列的祖先页改为了3列) 那么现在1行1列3行3列祖先都是3列,也就完成了剩余一个点的覆盖。(我们把两行两列都在一起记为四个顶点都被覆盖

所以最后只要跑一遍循环,看谁的祖先还是自己(没有和其他行列合并)就需要手动覆盖一个点

最后ans-1 我还没想出来为什么

猜你喜欢

转载自blog.csdn.net/baidu_41907100/article/details/85041279