1. 程式人生 > >【並查集】猜數

【並查集】猜數

【題目描述】

已知一個數列,我會告訴你某兩項的差,然後你要回答我的問題

【輸入格式】

第一行是兩個數 n,m,表示數列有n項,一共有m條指令。
接下來有m行,每行一個指令,指令分兩類:
1. I_i_j_k 表示第i比第j項大k.
2. A_i_j 詢問當前第i項與第j項差的絕對值.('_'表示空格)

【輸出格式】

對於每個2類指令,輸出一行,無法判斷時輸出-1


我們考慮用並查集來維護,我們維護他與根節點的相對大小

對於加法操作,我們先找到他們各自的根節點,如果不同,就對y點的祖先打上標記,因為我們要使x的查詢值比y大z,則應在y的祖先處打上的標記值為fr[x]-fr[y]-z

對於詢問操作,若不在並查集則輸出-1,否則輸出相對大小的絕對值差即可

#include<iostream>
#include<iomanip>
#include<cstring>
#include<cmath>
#include<cstdio>
#include<queue>
#include<algorithm>
#include<ctime>
using namespace std;
int n,m,f[10005],fr[10005];
char op[1];
int find(int x)
{
	if(x==f[x]) return x;
	int fx=find(f[x]);
	fr[x]+=fr[f[x]];
	f[x]=fx;
	return fx;
}
int main()
{
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++) f[i]=i,fr[i]=0;
	for(int i=1;i<=m;i++)
	{
		scanf("%s",op);
		if(op[0]=='I')
		{
			int x,y,z;
			scanf("%d%d%d",&x,&y,&z);
			int fx=find(x),fy=find(y);
			if(fx!=fy)
			{
				f[fy]=fx;
				fr[fy]=fr[x]-fr[y]-z;
			}
		}
		else
		{
			int x,y;
			scanf("%d%d",&x,&y);
			int fx=find(x),fy=find(y);
			if(fx!=fy) printf("-1\n");
			else printf("%d\n",abs(fr[x]-fr[y]));
		}
	}
}