Collect together (thought and simple examples)

Collect together (thought and simple examples)

Combining the collection, as the name implies, is the two functions of combining collections and searching collections.

Consolidation is generally used for connectivity issues (maybe I am too veteran)

First of all, we look at and find the search,

for example

Little Green is the boss of Little Red, Little Red is the boss of Little Blue, and Little Blue is the boss of Xiao Ming.

So little green, little red, little blue, and Xiao Ming, these four people are connected because of who is the boss.

The find function find() finds the top one connected to you//Who is your biggest boss

f[] array, used to store the last person connected to you//who is your boss

For example, f[小明]=little blue, f[little blue]=little red, f[little red]=little green

find[小明]=little green, find[little blue]=little green, find[little red]=little green;//In the final analysis, the boss of these people is small green

int f[maxn];
int find(int x)
{
 if(x==f[x])
 return x;
 else
 find(f[x]);
}//find函数


Next, take a look at the merge function join()

Today’s wind is very noisy, as expected, new people are here today

In this group, small a is the boss of small b, and small b is the boss of small c.

What should we do if we want to bring these two groups together?
Simple, just let them identify with a person as the boss, (boss a and little green can choose any one)

For example, let Xiao A recognize Xiao Lu as the boss. Then f[small a] = small green, then find (small b) = small green;

At this time, you need to use the join() function

The join function is to merge two sets, which is to make the boss with the largest set of one recognize the boss with the largest set of the other as the boss

void join(int x,int y)
{
    int a=find(x);
    int b=find(y);
    if(a!=b)
    f[a]=b;
}//这种有时会超内存,但不容易出错

void join(int x,int y)
{
f[find(x)]=find(y);
}//这种不容易超内存,但有时候会出问题

1. Template questions

https://www.acwing.com/problem/content/838/

There are n numbers in total, numbered from 1 to n, and each number is in a set at the beginning.

Now there are m operations to be performed. There are two operations:

  1. "M ab", merge the sets where the two numbers numbered a and b are located. If the two numbers are already in the same set, ignore this operation;
  2. "Q ab", asking whether the two numbers numbered a and b are in the same set;

Input format

Enter the integers n and m in the first line.

Next m lines, each line contains an operation instruction, the instruction is one of "M ab" or "Q ab".

Output format

For each query command "Q ab", a result must be output. If a and b are in the same set, output "Yes", otherwise output "No".

Each result is on one line.

data range

1≤n,m 1 0 5 10^5 105

#include<bits/stdc++.h>
using namespace std;
int f[100006];
// 该函数的含义:查找a所在集合的祖先节点下标,从1开始, 并内部更新f[a]为a节点的祖先节点。
int find(int a)
{
    // 根据通项公式,假设f[a]的祖先节点已知。
    if (f[a] != a) f[a] = find(f[a]);
    return f[a];
}
void join(int b,int c)
{
	int x=find(b);
	int y=find(c);
	if(x!=y)
	f[x]=y;
}

int main()
{
    int n, m;
    scanf("%d %d", &n, &m);

    // 初始化每个集合
    for (int i = 1; i <= n; i++) f[i] = i;

    int a, b;
    char op[2];
    while (m--)
    {
        scanf("%s%d%d", op, &a, &b);
        if (op[0] == 'M') join(a,b);
        else {
            if (find(a) == find(b)) puts("Yes");
            else puts("No");
        }
    }
    return 0;
}

Two, improve questions

https://www.acwing.com/problem/content/242/

There are three types of animals in the animal kingdom, A, B, and C. The food chain of these three types of animals forms an interesting ring.

A eats B, B eats C, and C eats A.

There are currently N animals, numbered from 1 to N.

Every animal is one of A, B, and C, but we don't know which one it is.

Some people describe the food chain relationship formed by these N animals in two ways:

The first statement is "1 XY", which means that X and Y are of the same kind.

The second statement is "2 XY", which means X eats Y.

This person uses the above two statements to say K sentences to N animals one after another. Some of these K sentences are true and some are false.

When a sentence satisfies one of the following three items, the sentence is false, otherwise it is true.

1) The current words conflict with some previous true words, which is a lie;
2) The current words X or Y is greater than N, which is a lie;
3) The current words mean that X eats X, which is a lie.

Your task is to output the total number of lies based on the given N and K sentences.

Input format

The first line is two integers N and K, separated by a space.

Each of the following K lines is three positive integers D, X, Y, separated by a space between the two numbers, where D represents the type of argument.

If D=1, it means that X and Y are of the same kind.

If D=2, it means X eats Y.

Output format

There is only one integer, which represents the number of lies.

data range

1≤N≤50000
0≤K≤100000

Input sample:

100 7
1 101 1 
2 1 2
2 2 3 
2 3 3 
1 1 3 
2 3 1 
1 5 5

Sample output:

3

answer

1. Consolidated search (expanded domain)//Generally, if there are multiple relationships, you can use expanded domain.
For this topic, we mainly want to open three extended domains, namely the homogeneous domain (1, n), the predator domain (n+1, 2n), and the natural enemy domain (2n+1, 3n).

That is, f[x] represents the relationship of the same kind, f[x+n] represents the relationship between predation, and f[x+2n] represents the relationship between natural enemies

If x and y are of the same kind, but the predator domain of x has y, then it
is wrong.If x and y are of the same kind, but the natural enemy domain of x has y, then the error is
if x is a natural enemy of y, but there is y in the same domain of x, Then it is wrong.
If x is a natural enemy of y, but there is y in the natural enemy domain of x, then the error

2. With the right to check the collection (described below)

In this question, the relative relationship is the relationship on the food chain. Therefore, the weight of the weighted and checked concentration should record the relative relationship between the two animals on the food chain. A->B is 0 for the same kind, and 1 for A eats B. 2 means that A is eaten by B. This value is different from the interval sum and score difference in the previous two questions. It cannot be added directly. Three questions should be considered:

1. How to update Value when path is compressed

If A->B is 1, and B->C is 1, how to find A->C? Obviously, A eats B and B eats C, then C should eat A according to the meaning of the question, then A->C should be 2;

If A->B is 2 and B->C is 2, how to find A->C? Obviously B eats A and C eats B, then A should eat C from the question, then A->C should be 1;

If A->B is 0 and B->C is 1, how to find A->C? Obviously, A and B are of the same kind, and B eats C, then A should eat C from the question, then A->C should be 1;

It is not difficult to find the rule, A->C = (A->B + B->C)% 3, so the update of the relationship value needs to be accumulated and modulo 3.

2. How to update Value when merging intervals

It is not difficult to find from 1 that the value update of this question is nothing more than an additional modulo operation, so it is not difficult to verify that the update operation of the interval merge should be:

value[px] = (-value[x] + value[y] + s)%3;//s represents the relationship between x and y

Extended domain code

#include<bits/stdc++.h>
using namespace std;
int f[200005];		
int d,x,y;
int n,k,sum=0;
int find(int a)
{
	if(a==f[a])
	return a;
	else
	find(f[a]);
}
void join(int a,int b)
{
	f[find(a)]=find(b);
}
int main()
{

	cin>>n>>k;
	for(int i=1;i<=3*n;i++)
	f[i]=i;
	while (k--)
	{
		scanf("%d%d%d",&d,&x,&y);
		if(x>n||y>n)
		sum++;
		else
		{
			if(d==1)
			{
			   if(find(x)==find(y+n)||find(x)==find(y+n+n))//如果x是在y的捕食域或者y的天敌域内就说明是错误的 
			   sum++;
			   else
			   {
			   	join(x,y);//表示x和y是同类 
			   	join(x+n,y+n);//x和y是同类,那么x和y的捕食域一样 
			   	join(x+n+n,y+n+n);//x和y的天敌域一样 
			   }
			}
			else
			{
				if(x==y||find(x)==find(y+n)||find(x)==find(y))//表示x等于y,x在y的捕食域,x和y是同类,三种情况 
				sum++;
				else
				{
					join(x+n,y);//y在x的捕食域 
					join(x,y+n+n);//x在y的天敌域 
					join(x+n+n,y+n);//x的天敌是在y的捕食域内 
				}
				
			}
	
		}
	}	
		cout<<sum<<endl;
	return 0;
}

Three, weighted and search set (merger and search have to update the weight)

Each edge records a weight value from each node to the root node. What the weight value should be set depends on the specific problem. Generally, it is a certain relative relationship between two nodes, but considering the weight There are two problems with the value:

1. Each node records the weight between the root node and the root node, so in the path compression process of Find, the weight should also be updated accordingly, because before path compression, each node is with its parent node Linked, the Value is naturally the weight between its parent node

2. When the two union check sets are merged, the weights must be updated accordingly, because the root nodes of the two union check sets are different.

Let's look at how to update the weight in these two processes:


int find(int x)
{
	if (x != f[x])
	{
		int t = f[x];
		f[x] = find(f[x]);//路径压缩
		value[x] += value[t];
	}
	return parent[x];
}

You can see that there are only two more lines of code to update the weight. First record the number of the original parent node, because the parent node becomes the root node after the path is compressed, and then add the weight of the current node to the weight of the original parent node. Value, at this time the weight of the parent node is already the weight from the parent node to the root node, so adding this weight will get the weight from the current node to the root node.

merge:


		int px = find(x);
		int py = find(y);
		if (px != py)
		{
			f[px] = py;
			value[px] = -value[x] + value[y] + s;//s表示x和y之间的关系
		}

Insert picture description here

It can be regarded as the addition and subtraction of vectors.

HihoCoder-1515-Score Investigation

description

Little Hi’s school has a total of N students, numbered 1-N. The school has just conducted a school-wide level test of ancient poetry.

The school did not announce the results of the test, so little Hi can only get some gossip, for example, the score of student X is higher than that of student Y by S points.

Little Hi wants to know if he can judge the scores between certain two classmates by using these news?

enter

The first line contains three integers N, M and Q. N represents the total number of students, M represents the total number of messages that little Hi knows, and Q represents the number of little Hi wants to ask.

The following M lines have three integers per line, X, Y, and S. It means that the score of student X is higher than that of student Y by S points.

The following Q lines each have two integers, X and Y. It means that Little Hi wants to know how much the score of student X is higher than that of student Y.

For 50% of the data, 1 <= N, M, Q <= 1000

For 100% data, 1 <= N, M, Q<= 100000 1 <= X, Y <= N -1000 <= S <= 1000

There are no contradictions in the data guarantee.

Output

For each query, if you cannot determine how much X is higher than Y, output -1. Otherwise, the score that X is higher than Y is output.

Sample input

10 5 3  
1 2 10  
2 3 10  
4 5 -10  
5 6 -10  
2 5 10  
1 10  
1 5  
3 5 

Sample output

-1  
20  
0
#include<bits/stdc++.h>
using namespace std; 
const int maxN = 100005;
int f[maxN];
int score[maxN];
int find(int x)
{
	if (x != f[x])
	{
		int t = f[x];
		f[x] = find(f[x]);
		score[x] += score[t];
	}
	return f[x];
}
int main()
{
	int n, m, q;
	scanf("%d%d%d", &n, &m, &q);
	for (int i = 1 ; i <= n ; i ++ )
	{
		f[i] = i;
	}
	while ( m-- )
	{
		int x, y, s;
		scanf("%d%d%d", &x, &y, &s);
		int px = find(x);
		int py = find(y);
		if (px != py)//合并 
		{
			f[px] = py;
			score[px] = -score[x] + score[y] + s;
		}
	}
	while (q --)
	{
		int x, y;
		scanf("%d%d",&x,&y);
		if (find(x) != find(y))
		{
			printf("-1\n");
		}
		else {
			printf("%d\n", score[x] - score[y]);
		}
	}	
	return 0;
}

 (int i = 1 ; i <= n ; i ++ )
	{
		f[i] = i;
	}
	while ( m-- )
	{
		int x, y, s;
		scanf("%d%d%d", &x, &y, &s);
		int px = find(x);
		int py = find(y);
		if (px != py)//合并 
		{
			f[px] = py;
			score[px] = -score[x] + score[y] + s;
		}
	}
	while (q --)
	{
		int x, y;
		scanf("%d%d",&x,&y);
		if (find(x) != find(y))
		{
			printf("-1\n");
		}
		else {
			printf("%d\n", score[x] - score[y]);
		}
	}	
	return 0;
}

Guess you like

Origin blog.csdn.net/hhuhgfhggy/article/details/109412999