题目传送门
。
解法:
我就写过一次带权并查集。
还好他不难想。。
看到这道题我就觉得是带权并查集。。。
fa[i]表示祖先。
sum[i]表示跟祖先的差值。
xx表示x的祖先,yy表示y的祖先。
那么每次x和y差w的时候
推式子?
x-xx=sum[x] – xx-x=-sum[x]
y-yy=sum[y]
y-x=w;
xx-yy?
将xx合并到yy。
xx-yy=sum[y]-sum[x]-w
那么sum[xx]也就等于这个。
然后询问的话判断是否在同一个集合里面。
代码实现:
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<queue>
using namespace std;
int sum[110000],fa[110000];
int findfa(int x) {
if(fa[x]!=x) {
int tt=fa[x];
fa[x]=findfa(fa[x]);sum[x]+=sum[tt];
}return fa[x];
}
int main() {
int n,m;
while(scanf("%d%d",&n,&m)&&n&&m) {
for(int i=1;i<=n;i++)fa[i]=i;memset(sum,0,sizeof(sum));
while(m--) {
char s[5];int a,b,w;
scanf("%s%d%d",s+1,&a,&b);
if(s[1]=='!') {
scanf("%d",&w);
int xx=findfa(a),yy=findfa(b);
if(xx!=yy) {fa[xx]=yy;sum[xx]=sum[b]-sum[a]-w;}
}
else {
int xx=findfa(a),yy=findfa(b);
if(xx!=yy)printf("UNKNOWN\n");
else printf("%d\n",sum[b]-sum[a]);
}
}
}
return 0;
}