HDU 3047 Zjnu Stadium [并查集]

http://acm.hdu.edu.cn/showproblem.php?pid=3047
#Description
有一个体育馆,每行300个坐位
来了N个人,提出M组要求
要求格式为 A B X
假设A的坐位是i, 则B的坐位是 i + X
如果来了一组要求和之前矛盾,忽略这组要求
问最终由多少组矛盾的要求
#Algorithm
带权并查集
用权V[i]表示X[id[i]] - X[i]
X[i] 为 第i个人做的位置

查找(find)时,启用路径压缩,则
v[p] = v[p] + v[t] t为之前的id[p]
因为路径压缩之后,id[p] == id[t] 假设 为 root
v[p] = x[root] - x[p]
v[t] = x[root] - x[t]
一开始
v[p] = x[t] - x[p]
所以 v[p] + v[t] = 新的v[p]

合并(unite)时,找的p, q的根i, j
如果 i == j
由于启用了路径压缩
v[p] = x[root] - x[p]
v[q] = x[root] - x[q]
定义 unite传入的参数x为 x[q] - x[p],
v[p] - v[q] = x[q] - x[p] 与 x 比较 不等则表示 这条信息矛盾
如果 i != j
那么就要根进行变化
使用加权并查集树的权值sz
假定sz[i] > sz[j] 即 root = i 的是大树,要将j 并到 i上去
id[j] = i;
sz[i] += sz[j];
关键是v[j]的变化
变化的v[j] = x[i] - x[j]
一开始v[j] = 0 因为v[j]是根
v[p] = x[i] - x[p]
v[q] = x[j] - x[q]
x = x[q] - x[p]
得到
v[j] = v[p] - x - v[q]
同理可得当 j 是大树的情况
#Code

  #include <iostream>
  #include <cstdio>
  using namespace std;
  const int MAXL = 50000;
  int ans;
  int n, m;
  int id[MAXL], sz[MAXL], v[MAXL]; //v[i] = x[id[i]] - x[i]
  void init(int n)
  {
    for (int i = 0; i < n; i++) {
      id[i] = i;
      sz[i] = 1;
      v[i] = 0;
    }
  }
  int find(int p)
  {
    if (p != id[p]) {
      int t = id[p];
      id[p] = find(id[p]);
      v[p] += v[t];
    }
    return id[p];
  }
  void unite(int p, int q, int x)
  {
    int i = find(p), j = find(q);
    if (i == j) {
      if (v[p] - v[q] != x) {
        ans++;
      }
      return;
    }
    if (sz[i] > sz[j]) {
      id[j] = i;
      sz[i] += sz[j];
      v[j] = v[p] - x - v[q];
    } else
    {
      id[i] = j;
      sz[j] += sz[i];
      v[i] = v[q] + x - v[p];
    }
  }
  void solve()
  {
    ans = 0;
    init(n);
    while (m--) {
      int a, b, x;
      scanf("%d%d%d", &a, &b, &x);
      a--;
      b--;
      unite(a, b, x);
    }
    printf("%d\n", ans);
  }
  int main()
  {
   // freopen("in.txt", "r", stdin);
    while (scanf("%d%d", &n, &m) != EOF) {
      solve();
    }
  }

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值