题目
题目传送门:
http://hihocoder.com/problemset/problem/1515
1515 : 分数调查
时间限制:10000ms
单点时限:1000ms
内存限制:256MB
描述
小Hi的学校总共有N名学生,编号1-N。学校刚刚进行了一场全校的古诗文水平测验。
学校没有公布测验的成绩,所以小Hi只能得到一些小道消息,例如X号同学的分数比Y号同学的分数高S分。
小Hi想知道利用这些消息,能不能判断出某两位同学之间的分数高低?
输入
第一行包含三个整数N, M和Q。N表示学生总数,M表示小Hi知道消息的总数,Q表示小Hi想询问的数量。
以下M行每行三个整数,X, Y和S。表示X号同学的分数比Y号同学的分数高S分。
以下Q行每行两个整数,X和Y。表示小Hi想知道X号同学的分数比Y号同学的分数高几分。
对于50%的数据,1 <= N, M, Q <= 1000
对于100%的数据,1 <= N, M, Q<= 100000 1 <= X, Y <= N -1000 <= S <= 1000
数据保证没有矛盾。
输出
对于每个询问,如果不能判断出X比Y高几分输出-1。否则输出X比Y高的分数。
样例输入
10 5 3
1 2 10
2 3 10
4 5 -10
5 6 -10
2 5 10
1 10
1 5
3 5
样例输出
-1
20
0
题解
带权并查集裸题
主要就是比普通的并查集多了权值关系的连接
一个注意点就是在find函数路径压缩的时候需要对权值进行更新
核心部分是merge函数的两个计算公式,这个可以现推,并不难
fx-fy=val-v[x]+v[y]
fy-fx=v[x]-v[y]-val
当然如果你愿意放弃rank数组的优化可以只用第一个公式
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68
| #include <iostream> #include <cstdio> #include <cstring> using namespace std; const int maxn=(int)1e5+10;
int f[maxn],r[maxn],v[maxn];
void init(int n){ for(int i=0;i<n;i++) f[i]=i,r[i]=0,v[i]=0; }
int find(int x){ if(f[x]==x) return x; else{ int t=f[x]; f[x]=find(f[x]); v[x]+=v[t]; return f[x]; } }
void merge(int x,int y,int val){ int fx=find(x); int fy=find(y); if(fx!=fy){ if(r[fx]<r[fy]){ f[fx]=fy; v[fx]=val-v[x]+v[y]; } else{ f[fy]=fx; v[fy]=v[x]-v[y]-val; if(r[fx]==r[fy]) r[fx]++; } } }
bool same(int x,int y){ return find(x)==find(y); }
int main(){ int n,m,q; while(~scanf("%d%d%d",&n,&m,&q)){ init(n); int x,y,val; while(m--){ scanf("%d%d%d",&x,&y,&val); merge(x,y,val); } while(q--){ scanf("%d%d",&x,&y); int fx=find(x); int fy=find(y); if(fx!=fy) printf("-1\n"); else printf("%d\n",v[x]-v[y]); } } return 0; }
|