题目大意
一堆未知数,之间有权值关系如x-y=z
每次给出关系或询问两个未知数的差
权值并查集
关系的维护显然用并查集。
每个节点维护如果父亲权值为0我的权值应该是多少即可。
#include<cstdio>
#include<algorithm>
#define fo(i,a,b) for(i=a;i<=b;i++)
using namespace std;
const int maxn=100000+10;
int fa[maxn],data[maxn],rank[maxn];
int i,j,k,l,t,n,m;
char ch;
int read(){
int x=0,f=1;
char ch=getchar();
while (ch<'0'||ch>'9'){
if (ch=='-') f=-1;
ch=getchar();
}
while (ch>='0'&&ch<='9'){
x=x*10+ch-'0';
ch=getchar();
}
return x*f;
}
char get(){
char ch=getchar();
while (ch!='!'&&ch!='?') ch=getchar();
return ch;
}
int getfa(int x){
if (!fa[x]) return x;
int y=getfa(fa[x]);
data[x]+=data[fa[x]];
return fa[x]=y;
}
void merge(int x,int y,int z){
int a=getfa(x),b=getfa(y);
if (a==b) return;
if (rank[a]>rank[b]){
swap(a,b);
swap(x,y);
z=-z;
}
fa[a]=b;
data[a]+=data[y]-data[x]-z;
if (rank[a]==rank[b]) rank[b]++;
}
int main(){
while (1){
n=read();m=read();
if (!n) break;
fo(i,1,n) fa[i]=rank[i]=data[i]=0;
while (m--){
ch=get();
if (ch=='!'){
j=read();k=read();l=read();
merge(j,k,l);
}
else{
j=read();k=read();
if (getfa(j)!=getfa(k)) printf("UNKNOWN\n");
else printf("%d\n",data[k]-data[j]);
}
}
}
}