1202: [HNOI2005]狡猾的商人
Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 3052 Solved: 1444
[ 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
题目大意:
如题。
思路:
之前做过一个类似的题目,那个是要求找出有多少错误的答案。这个只需要判断是否正确就可以了。
根据并查集的路径压缩法,对于某个区间,我们看起点和终点是否连通,如果连通,就检查他们之间的权值是否为给出的权值。
如果不连通,我们把起点和终点连通,
我们在路径压缩的时候更新出 当前节点到其父节点上的权值。
还有就是为什么要将区间左端点缩一下,因为我们这样表示的是一个闭区间 例如 3 - 5 1 - 2
我们想要把他表示为 2 - 5 0 - 2 这样将区间连起来,才可以用并查集来表示。
AC代码:
#include <iostream>
#include<stdio.h>
#include<math.h>
using namespace std;
const int MAX = 200000;
int n,m,k;
int parent[MAX+10];
int val[MAX+10];
int GetParent(int a)
{
if( parent[a]== a)
return parent[a];
int t= GetParent(parent[a]);
val[a]+=val[parent[a]];
parent[a]=t;
return t;
}
int Merge(int a,int b,int c)
{
int p1 = GetParent(a);
int p2 = GetParent(b);
if( p1 == p2 )
{
if(val[a]-val[b]==c)
return 0;
return 1;
}
parent[p1] = p2;
val[p1]=c+val[b]-val[a];
return 0;
}
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
scanf("%d%d",&n,&m);
for(int i = 0;i <=n; ++i)
{
parent[i] = i;
val[i]=0;
}
int work=0;
for(int i = 0;i < m; ++i)
{
int k,h,s;
scanf("%d",&k);
scanf("%d",&h);
scanf("%d",&s);
k--;
if(Merge(k,h,s))
{
work=1;
break;
}
}
if(work)
puts("false");
else
puts("true");
}
return 0;
}