結果
| 問題 |
No.416 旅行会社
|
| コンテスト | |
| ユーザー |
norioc
|
| 提出日時 | 2018-01-13 12:28:12 |
| 言語 | D (dmd 2.109.1) |
| 結果 |
AC
|
| 実行時間 | 490 ms / 4,000 ms |
| コード長 | 3,520 bytes |
| コンパイル時間 | 1,029 ms |
| コンパイル使用メモリ | 108,468 KB |
| 実行使用メモリ | 28,800 KB |
| 最終ジャッジ日時 | 2024-06-12 23:34:05 |
| 合計ジャッジ時間 | 6,812 ms |
|
ジャッジサーバーID (参考情報) |
judge1 / judge3 |
(要ログイン)
| ファイルパターン | 結果 |
|---|---|
| other | AC * 21 |
ソースコード
import std.algorithm;
import std.array;
import std.conv;
import std.math;
import std.range;
import std.stdio;
import std.string;
import std.typecons;
int readint() { return readln.chomp.to!int; }
int[] readints() { return readln.split.to!(int[]); }
alias Pair = Tuple!(int, "a", int, "b");
Pair readpair() {
auto xs = readints;
return Pair(xs[0], xs[1]);
}
void main() {
auto nmq = readints;
int n = nmq[0], m = nmq[1], q = nmq[2];
Pair[] pairs;
for (int i = 0; i < m; i++) {
pairs ~= readpair();
}
bool[Pair] breakMap;
Pair[] breaks;
for (int i = 0; i < q; i++) {
auto p = readpair();
breaks ~= p;
breakMap[p] = true;
}
auto uf = new UnionFind(n);
foreach (p; pairs) {
// 破壊に関係ない橋を予め接続しておく
if (p !in breakMap) {
uf.unite(p.a, p.b);
}
}
auto ans = new int[](n + 1);
ans[] = -1; // 全て到達できる
foreach_reverse (i, brk; breaks) {
const rootA = uf.root(brk.a);
const rootB = uf.root(brk.b);
const root1 = uf.root(1);
if (rootA != rootB && (rootA == root1 || rootB == root1)) {
int nth = cast(int) i + 1;
int node = rootA == root1 ? rootB : rootA; // 1 と接続された集合のルート
/*
foreach (x; uf.group(node)) {
ans[x] = nth;
}*/
uf.doEach(node, delegate(e) { ans[e] = nth; });
}
uf.unite(brk.a, brk.b);
}
for (int i = 2; i <= n; i++) {
if (uf.isSame(1, i))
writeln(ans[i]);
else
writeln(0); // 最初から到達できない
}
}
class SList {
public int node;
public SList next;
public SList tail;
this(int node) {
this.node = node;
this.next = null;
this.tail = this;
}
/// 引数 list を破壊的に変更する
void append(SList list) {
this.tail.next = list;
this.tail = list.tail;
}
int[] toArray() {
int[] buf = [node];
auto p = this.next;
while (p !is null) {
buf ~= p.node;
p = p.next;
}
return buf;
}
}
class UnionFind {
private int[] _data;
private int[] _nexts; // 次の要素。なければ -1
private int[] _tails; // 末尾の要素
this(int n) {
_data = new int[](n + 1);
_nexts = new int[](n + 1);
_tails = new int[](n + 1);
_data[] = -1;
_nexts[] = -1;
for (int i = 0; i < _tails.length; i++)
_tails[i] = i;
}
int root(int a) {
if (_data[a] < 0) return a;
return _data[a] = root(_data[a]);
}
bool unite(int a, int b) {
int ra = root(a);
int rb = root(b);
if (ra == rb) return false;
// ra に rb を繋げる
_data[ra] += _data[rb];
_data[rb] = ra;
// ra の末尾の後ろに rb を繋げる
_nexts[_tails[ra]] = rb;
// ra の末尾が rb の末尾になる
_tails[ra] = _tails[rb];
return true;
}
bool isSame(int a, int b) {
return root(a) == root(b);
}
/// a が属する集合のサイズ
int groupSize(int a) {
return -_data[root(a)];
}
void doEach(int a, void delegate(int) fn) {
auto node = root(a);
while (node != -1) {
fn(node);
node = _nexts[node];
}
}
}
norioc