BZOJ1202: [HNOI2005]狡猾的商人(带权并查集)
***姹接到一个任务,为税务部门调查一位商人的账本,看看账本是不是伪造的。账本上记录了n个月以来的收入情况,其中第i 个月的收入额为Ai(i=1,2,3...n-1,n), 。当 Ai大于0时表示这个月盈利Ai 元,当 Ai小于0时表示这个月亏损Ai 元。所谓一段时间内的总收入,就是这段时间内每个月的收入额的总和。 ***姹的任务是秘密进行的,为了调查商人的账本,她只好跑到商人那里打工。她趁商人不在时去偷看账本,可是她无法将账本偷出来,每次偷看账本时她都只能看某段时间内账本上记录的收入情况,并且她只能记住这段时间内的总收入。 现在,***姹总共偷看了m次账本,当然也就记住了m段时间内的总收入,你的任务是根据记住的这些信息来判断账本是不是假的。
题解:不会做 学习了一波 val(i)表示i距离他父亲的距离
利用并查集 每次给的一个区间如果不在同一个集合就把区间左端点并到右端点上 更新左端点的val(l)
如果在同一个区间 那么l到父亲的距离减去r到父亲的距离就是区间长度
利用这个来判断账本合不合法就好了
#include <bits/stdc++.h> using namespace std; int pre[105], val[105]; int find(int x) { if(x == pre[x]) return x; else { int fa = find(pre[x]); val[x] += val[pre[x]]; pre[x] = fa; return fa; } } int main() { int T; scanf("%d", &T); while(T--) { int n, m; scanf("%d%d", &n, &m); for(int i = 0; i <= n; i++) pre[i] = i; memset(val, 0, sizeof(val)); bool f = true; for(int i = 1; i <= m; i++) { int s, t, w; scanf("%d%d%d", &s, &t, &w); int ax = find(s - 1); int bx = find(t); if(ax != bx) { pre[ax] = bx; val[ax] = w + val[t] - val[s - 1]; } else if(val[s - 1] - val[t] != w) f = false; } if(f) puts("true"); else puts("false"); } return 0; }