URAL 1701 Ostap and Partners(差统计量的并查集)

题目大意:

几个人在谈论他们的工资, 他会告诉你很多句话, 每句话是 a 比 b 多 c 块钱. 已知没有人的工资低于0或高于 10^9.  第一个人工资是0。 问从第几句话开始你可以判断有人在吹牛.如果没人吹牛输出每个人的工资。

解法:维护每个节点到根节点的差,判矛盾的方法类似于普通的种类并查集。最后还要判如果以上描述正确是否一定有人的工资超出了范围(这种矛盾只有可能在所有关系都给出后才能判断,中间无法判断)。因为第一个人的工资一定,因此会顶合并是总让标号小的做根节点,这样就可以固定第一个人的值。

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.StreamTokenizer;

public class OstapandPartners1701 {
	int p[], k[], min[];

	int find(int x) {
		if (x == p[x])
			return x;
		int temp = p[x];
		p[x] = find(temp);
		k[x] += k[temp];
		return p[x];
	}

	boolean merge(int a, int b, int v) {
		int pa = find(a);
		int pb = find(b);
		if (pa == pb)
			return true;
		if (pa < pb) {
			int temp = pa;
			pa = pb;
			pb = temp;
			temp = a;
			a = b;
			b = temp;
			v = -v;
		}
		p[pa] = pb;
		k[pa] = v - k[a] + k[b];
		return false;
	}

	StreamTokenizer in = new StreamTokenizer(new BufferedReader(
			new InputStreamReader(System.in)));

	final int next() throws IOException {
		in.nextToken();
		return (int) in.nval;
	}

	void run() throws IOException {
		int n = next();
		int m = next();
		int inf = 1000000000;
		p = new int[n];
		k = new int[n];
		min = new int[n];
		for (int i = 0; i < n; i++)
			p[i] = i;

		boolean flag = false;
		int a, b, v;
		for (int i = 1; i <= m; i++) {
			a = next();
			b = next();
			v = next();
			if (flag)
				continue;
			if (merge(a, b, v) && k[a] - k[b] != v) {
				flag = true;
				System.out.println("Impossible after " + i + " statements");
			}
		}
		if (flag)
			return;
		int res[] = new int[n];
		for (int i = 0; i < n; i++) {
			int x = find(i);
			if (k[i] < min[x])
				min[x] = k[i];
		}
		for (int i = 0; i < n; i++)
			if (p[i] == i && min[i] < 0)
				res[i] = -min[i];
		res[0] = 0;
		for (int i = 0; i < n; i++) {
			res[i] = res[p[i]] + k[i];
			if (res[i] > inf || res[i] < 0)
				flag = true;
		}
		if (flag)
			System.out.println("Impossible after " + m + " statements");
		else {
			System.out.println("Possible");
			for (int i = 0; i < n; i++)
				System.out.println(res[i]);
		}
	}
	public static void main(String[] args) throws IOException {
		new OstapandPartners1701().run();
	}
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值