类型:并查集
题目:http://acm.hdu.edu.cn/showproblem.php?pid=3038
来源: 2009 Multi-University Training Contest 13 - Host by HIT思路:
(1)右端点为根,左端点为叶子
(2)sum[a]表示区间[a + 1, a的父亲节点]的序列的和(3)路径压缩的同时更新sum的值
(4)对于新输入端节点,如果两端节点在同一联通分量中,根据计算判断输入和是否合法,不在同一联通分量中,合并,并更新sum值

// hdoj 3038 How Many Answers Are Wrong
// ac 31MS 1592K
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
#define FOR(i,a,b) for(i = (a); i < (b); ++i)
#define FORE(i,a,b) for(i = (a); i <= (b); ++i)
#define FORD(i,a,b) for(i = (a); i > (b); --i)
#define FORDE(i,a,b) for(i = (a); i >= (b); --i)
#define CLR(a,b) memset(a,b,sizeof(a))
const int MAXN = 200100;
int p[MAXN], sum[MAXN], ans, n, m;
void init() {
int i;
ans = 0;
CLR(sum, 0);
FORE(i, 0, n)
p[i] = i;
}
int find_set(int x) {
if (p[x] == x)
return x;
int t = p[x];
p[x] = find_set(p[x]);
sum[x] += sum[t];
return p[x];
}
void union_set(int a, int b, int pa, int pb, int c) {
if (pa > pb) {
p[pb] = pa;
sum[pb] = sum[a] - sum[b] - c;
}
else {
p[pa] = pb;
sum[pa] = sum[b] + c - sum[a];
}
}
int main() {
int i, a, b, c, pa, pb;
while (scanf("%d %d", &n, &m) != EOF) {
init();
FOR(i, 0, m) {
scanf("%d %d %d", &a, &b, &c);
a--;
pa = find_set(a);
pb = find_set(b);
if (pa == pb) {
if (sum[a] != sum[b] + c) {
ans++;
}
}
else
union_set(a, b, pa, pb, c);
}
printf("%d\n", ans);
}
return 0;
}

本文介绍了一种使用并查集解决区间求和问题的方法。通过将右端点作为根节点,左端点作为叶子节点,利用路径压缩优化查找效率,并在合并节点时更新区间和。适用于处理动态区间操作及验证输入合法性。


被折叠的 条评论
为什么被折叠?



