HDU ~ 3038 ~ How Many Answers Are Wrong (带权并查集)
2018-01-18 17:14
155 查看
题意:有N个数字,M组关系。每组关系三个数字a,b,s表示a~b的和为s。问与前面产生矛盾的话有几组?
思路:带权并查集。多开一个权值数组,存储到自己和父节点的区间和。
图一:路径压缩,b~root的和 = b~a的和 + a ~ root的和。
图二:合并操作,现在我们知道a~root1和b~root2的区间和,又告诉了我们a~b的区间和,把root2并到root1上的话,
root1~root2的区间和为 (a~b)+ (b~root2) - (a~root1)。
图三:求a~b的区间和,a~b的和 = (a~root) - (b ~ root)的和。
![](https://img-blog.csdn.net/20180118170639909?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvWnNjRHN0/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
#include<bits/stdc++.h>
using namespace std;
const int MAXN = 200005;
int n, m, ans, f[MAXN], w[MAXN];//并查集数组和关系数组
//w[i]表示跟根节点的差
void init()
{
ans = 0;
for (int i = 0; i <= n; i++)
{
f[i] = i; w[i] = 0;
}
}
int Find(int x)
{
if (f[x] == x) return x;
int t = f[x];
f[x] = Find(f[x]);
w[x] = w[x] + w[t];
return f[x];
}
void Union(int a, int b, int s)
{
int root1 = Find(a), root2 = Find(b);
if (root1 != root2)
{
f[root1] = root2;
w[root1] = w[b] + s - w[a];
}
else
{
if (abs(w[a] - w[b]) != s) ans++;
}
}
int main()
{
while(~scanf("%d%d", &n, &m))
{
init();//初始化
while (m--)
{
int a, b, s;
scanf("%d%d%d", &a, &b, &s);
Union(a - 1, b, s);//a~b的区间和为w[b] - w[a - 1]
}
printf("%d\n", ans);
}
return 0;
}
/*
10 5
1 10 100
7 10 28
1 3 32
4 6 41
6 6 1
*/
4000
思路:带权并查集。多开一个权值数组,存储到自己和父节点的区间和。
图一:路径压缩,b~root的和 = b~a的和 + a ~ root的和。
图二:合并操作,现在我们知道a~root1和b~root2的区间和,又告诉了我们a~b的区间和,把root2并到root1上的话,
root1~root2的区间和为 (a~b)+ (b~root2) - (a~root1)。
图三:求a~b的区间和,a~b的和 = (a~root) - (b ~ root)的和。
#include<bits/stdc++.h>
using namespace std;
const int MAXN = 200005;
int n, m, ans, f[MAXN], w[MAXN];//并查集数组和关系数组
//w[i]表示跟根节点的差
void init()
{
ans = 0;
for (int i = 0; i <= n; i++)
{
f[i] = i; w[i] = 0;
}
}
int Find(int x)
{
if (f[x] == x) return x;
int t = f[x];
f[x] = Find(f[x]);
w[x] = w[x] + w[t];
return f[x];
}
void Union(int a, int b, int s)
{
int root1 = Find(a), root2 = Find(b);
if (root1 != root2)
{
f[root1] = root2;
w[root1] = w[b] + s - w[a];
}
else
{
if (abs(w[a] - w[b]) != s) ans++;
}
}
int main()
{
while(~scanf("%d%d", &n, &m))
{
init();//初始化
while (m--)
{
int a, b, s;
scanf("%d%d%d", &a, &b, &s);
Union(a - 1, b, s);//a~b的区间和为w[b] - w[a - 1]
}
printf("%d\n", ans);
}
return 0;
}
/*
10 5
1 10 100
7 10 28
1 3 32
4 6 41
6 6 1
*/
4000
相关文章推荐
- HDU 3038 How Many Answers Are Wrong (并查集路径压缩)
- HDU 3038 带权并查集,区间
- hdu 3038 How Many Answers Are Wrong (带权并查集)
- HDU 3038 How Many Answers Are Wrong 带权并查集
- HDU 3038 How Many Answers Are Wrong(并查集)
- HDU - 3038 How Many Answers Are Wrong (带权并查集)
- hdu 3038 How Many Answers Are Wrong 并查集
- hdu 3038 hdu 3047 poj 1192 带权并查集
- 【HDU 3038 How Many Answers Are Wrong】+ 并查集
- hdu 3038 How Many Answers Are Wrong (带权并查集)
- hdu 3038(扩展并查集)
- HDU---3038(并查集好题)
- HDU 3038 带权并查集
- HDU 3038 带权并查集,区间
- HDU 3038 How Many Answers Are Wrong (并查集)---并查集看不出来系列-1
- HDU 3038 How Many Answers Are Wrong(并查集)
- D - How Many Answers Are Wrong HDU - 3038(带权并查集)
- D - How Many Answers Are Wrong HDU - 3038 带权并查集
- 并查集【路径迭代】HDU 3038 How Many Answers Are Wrong
- How Many Answers Are Wrong HDU - 3038 (并查集)题解