题意:n个数的序列,进行m次查询,判断m次查询中有几次是错的。每次查询给出子序列的左端点a,右端点b和[a,b]的区间和s。
题解:带权并查集
1.当a和b同时出现过且根节点相同才可以判断是否错误。画个图就知道了。
2.权值代表该端点与根节点的距离。因为是闭区间所以查询[a,b]的区间和,等于查询a-1和b的距离。这个距离其实就是区间和,由于负数的存在使这道题必须两个端点都出现过才能判断是否错误。具体细节在代码中。
3.这道题最坑的地方在题目中只给了一个测例,却有多组测例输出。
#include<math.h>
#include<stdio.h>
#include<algorithm>
#include<string.h>
#include<vector>
#define N 200005
using namespace std ;
int n , k ;
int ans = 0 ;
struct Node
{
int pre ;
int sum ;
} node[N] ;
int find(int x)
{
int temp = x ;
int t = node[temp].pre ;
if(x == node[x].pre)
return x ;
while(x != node[x].pre)
x = node[x].pre ;
node[temp].pre = find(node[temp].pre) ;
node[temp].sum += node[t].sum ;
return x ;
}
void union1(int u , int v , int s)
{
int ru , rv ;
ru = find(u) ;
rv = find(v) ;
if(ru == rv)
{
if(node[u].sum + s != node[v].sum)
ans ++ ;
}
else
{
if(ru < rv)
{
node[rv].pre = ru ;
node[rv].sum = node[u].sum - (node[v].sum - s) ;
}
else
{
node[ru].pre = rv ;
node[ru].sum = node[v].sum - node[u].sum - s ;
}
}
}
int main()
{
int i , j ;
int u , v , s ;
ans = 0 ;
for(i = 0 ; i <= n ; i ++)
{
node[i].pre = i ;
node[i].sum = 0 ;
}
for(i = 0 ; i < k ; i ++)
{
scanf("%d%d%d" , &u , &v , &s) ;
union1(u - 1 , v , s) ;
}
printf("%d\n" , ans) ;
}