其实就是并查集的题。维护一个前缀和,然后用并查集维护前缀和,每次判断是否合理就行了。
题干:
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 2 3 3 1 2 10 1 3 -5 3 3 -15 5 3 1 5 100 3 5 50 1 2 51 Sample Output true false HINT
代码:
#include<iostream> #include<cstdio> #include<cmath> #include<ctime> #include<queue> #include<algorithm> #include<cstring> using namespace std; #define duke(i,a,n) for(int i = a;i <= n;i++) #define lv(i,a,n) for(int i = a;i >= n;i--) #define clean(a) memset(a,0,sizeof(a)) const int INF = 1 << 30; typedef long long ll; typedef double db; template <class T> void read(T &x) { char c; bool op = 0; while(c = getchar(), c < '0' || c > '9') if(c == '-') op = 1; x = c - '0'; while(c = getchar(), c >= '0' && c <= '9') x = x * 10 + c - '0'; if(op) x = -x; } template <class T> void write(T x) { if(x < 0) putchar('-'), x = -x; if(x >= 10) write(x / 10); putchar('0' + x % 10); } int fa[1050],n,m,t,flag = 0; int v[1050]; int find(int x) { if(fa[x] == x) { return x; } t = find(fa[x]); v[x] += v[fa[x]]; fa[x] = t; return fa[x]; } void work(int x,int y,int z) { int p = find(x); int q = find(y); if(p != q) { fa[p] = q; v[p] = v[y] - v[x] - z; } else if(v[y] - v[x] != z) flag = 1; } int main() { int w,x,y,z; read(w); while(w--) { flag = 0; clean(v); read(n);read(m); duke(i,0,n) fa[i] = i; duke(i,1,m) { read(x);read(y);read(z); work(x - 1,y,z); } if(flag) printf("false "); else printf("true "); } return 0; } /* 2 3 3 1 2 10 1 3 -5 3 3 -15 5 3 1 5 100 3 5 50 1 2 51 */