BZOJ1202: [HNOI2005]狡猾的商人
1202: [HNOI2005]狡猾的商人
Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 4198 Solved: 2026
[Submit][Status][Discuss]
Description
*** 姹接到一个任务,为税务部门调查一位商人的账本,看看账本是不是伪造的。账本上记录了n个月以来的收入情况,其中第i 个月的收入额为Ai(i=1,2,3...n-1,n), 。当 Ai大于0时表示这个月盈利Ai 元,当 Ai小于0时表示这个月亏损Ai 元。所谓一段时间内的总收入,就是这段时间内每个月的收入额的总和。 ***姹的任务是秘密进行的,为了调查商人的账本,她只好跑到商人那里打工。她趁商人不在时去偷看账本,可是她无法将账本偷出来,每次偷看账本时她都只能看某 段时间内账本上记录的收入情况,并且她只能记住这段时间内的总收入。 现在,***姹总共偷看了m次账本,当然也就记住了m段时间内的总收入,你的任务是根据记住的这些信息来判断账本是不是假的。
Input
第 一行为一个正整数w,其中w < 100,表示有w组数据,即w个账本,需要你判断。每组数据的第一行为两个正整数n和m,其中n < 100,m < 1000,分别表示对应的账本记录了多少个月的收入情况以及偷看了多少次账本。接下来的m行表示***姹偷看m次账本后记住的m条信息,每条信息占一行,有三 个整数s,t和v,表示从第s个月到第t个月(包含第t个月)的总收入为v,这里假设s总是小于等于t。
Output
包含w行,每行是true或false,其中第i行为true当且仅当第i组数据,即第i个账本不是假的;第i行为false当且仅当第i组数据,即第i个账本是假的。
Sample Input
3 3
1 2 10
1 3 -5
3 3 -15
5 3
1 5 100
3 5 50
1 2 51
Sample Output
false
HINT
Source
【题解】
一眼并查集,而眼部分和->前缀和常见套路。
对于Σl..r = w
拆成pre[r] - pre[l - 1]
其中pre[i] = num[1] + num[2] + ... + num[i - 1] + num[i]
用加权并查集维护前缀和
即若fa[f1] = f2, 则pre[f2] - pre[f1] = val[cnt1]
val[i]表示i到他父亲的权重
推一推式子就能维护了
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <cstdlib> 5 #include <algorithm> 6 #include <queue> 7 #include <vector> 8 #define min(a, b) ((a) < (b) ? (a) : (b)) 9 #define max(a, b) ((a) > (b) ? (a) : (b)) 10 #define abs(a) ((a) < 0 ? (-1 * (a)) : (a)) 11 inline void swap(int &a, int &b) 12 { 13 int tmp = a;a = b;b = tmp; 14 } 15 inline void read(int &x) 16 { 17 x = 0;char ch = getchar(), c = ch; 18 while(ch < '0' || ch > '9') c = ch, ch = getchar(); 19 while(ch <= '9' && ch >= '0') x = x * 10 + ch - '0', ch = getchar(); 20 if(c == '-') x = -x; 21 } 22 23 const int INF = 0x3f3f3f3f; 24 const int MAXN = 100 + 10; 25 26 int fa[MAXN], val[MAXN], n, m; 27 28 int find(int x) 29 { 30 if(x == fa[x]) return x; 31 int f = find(fa[x]); 32 val[x] += val[fa[x]]; 33 fa[x] = f; 34 return f; 35 } 36 37 int main() 38 { 39 int t;read(t); 40 for(;t;--t) 41 { 42 read(n), read(m); 43 for(register int i = 0;i <= n;++ i) fa[i] = i, val[i] = 0; 44 for(register int i = 1;i <= m;++ i) 45 { 46 int l,r,w; 47 read(l), read(r), read(w); 48 int f1 = find(l - 1), f2 = find(r); 49 if(f1 != f2) 50 { 51 fa[f1] = f2; 52 val[f1] = w + val[r] - val[l - 1]; 53 } 54 else 55 { 56 if(val[l - 1] - val[r] != w) 57 { 58 printf("false\n"); 59 break; 60 } 61 } 62 if(i == m) printf("true\n"); 63 } 64 } 65 return 0; 66 }