有一个长度已知的整数串,给出一系列包含\(l,r\)的语句,表示\([l,r]\)这个区间的和。问有多少条语句是错误的。
多组输入!!!
数据只有\(2×10^5\)这么大,不用离散化了。
因为和这题差不多,所以就只简单地写一下关键点。
区间处理
为了能够连通,给出的闭区间\([u,v]\)要改成\((u-1,v]\)。
路径压缩的关系维护:
假设已知0~3的和以及3~5的和,两个加起来就是0~5的和
合并时的关系维护:
假设已知0~3的和、4~7的和、0~4的和,求3~7的和。嗯,小学数学题。
查询时的关系计算:
做题的时候这里没想清楚就写上去了导致没有1A……唉
计算的前提是两端点的根节点相同,也就是说,分别以这两个端点为左端点的两个区间有相同的右端点,所以:
然后将这个结果与给出的和比较是否相同就行了。
int n, m;
int rela[maxn], fa[maxn];
int find(int x) {
if (fa[x] == -1) return x;
int tmp = find(fa[x]);
rela[x] = rela[x] + rela[fa[x]];
return fa[x] = tmp;
}
bool merge(int u, int v, int s) {
int r1 = find(u);
int r2 = find(v);
if (r1 == r2) {
return s == rela[u] - rela[v];
}
else {
fa[r1] = r2;
rela[r1] = s + rela[v] - rela[u];
//已知(0,3]为4,(5,7]为8,又(1,5]为7,则(3,7]为7+8-4=11
return true;
}
}
int main()
{
//ios::sync_with_stdio(false);
while (cin >> n >> m) {
int ans = 0;
memset(rela, 0, sizeof(rela));
for (int i = 0; i <= n; i++) fa[i] = -1;
//注意0也要初始化
for (int i = 1; i <= m; i++) {
int u, v, s;
cin >> u >> v >> s;
if (u > v) swap(u, v);
if (!merge(u - 1, v, s)) ans++;
}
cout << ans << endl;
}
return 0;
}
【带权并查集】How Many Answers Are Wrong HDU - 3038
原文:https://www.cnblogs.com/streamazure/p/13467202.html