結果
| 問題 |
No.416 旅行会社
|
| コンテスト | |
| ユーザー |
|
| 提出日時 | 2016-09-09 19:33:32 |
| 言語 | C++14 (gcc 13.3.0 + boost 1.87.0) |
| 結果 |
AC
|
| 実行時間 | 508 ms / 4,000 ms |
| コード長 | 3,144 bytes |
| コンパイル時間 | 2,117 ms |
| コンパイル使用メモリ | 188,684 KB |
| 実行使用メモリ | 26,628 KB |
| 最終ジャッジ日時 | 2024-12-14 20:15:33 |
| 合計ジャッジ時間 | 7,837 ms |
|
ジャッジサーバーID (参考情報) |
judge2 / judge5 |
(要ログイン)
| ファイルパターン | 結果 |
|---|---|
| other | AC * 21 |
ソースコード
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define rep(i,n) for(int (i)=0;(i)<(int)(n);++(i))
#define each(itr,c) for(__typeof(c.begin()) itr=c.begin(); itr!=c.end(); ++itr)
#define all(x) (x).begin(),(x).end()
#define pb push_back
#define fi first
#define se second
typedef pair<int,int> pi;
typedef vector<int> vi;
struct UF{
int n;
//正だったらその頂点の親,負だったら根で連結成分の個数
vector<int> d;
UF() {}
UF(int N):n(N), d(N,-1){}
int root(int v){
if(d[v]<0) return v;
return d[v]=root(d[v]);
}
bool unite(int X,int Y){
X=root(X); Y=root(Y);
if(X==Y) return false;
if(size(X) < size(Y)) swap(X,Y);
d[X]+=d[Y];
d[Y]=X;
return true;
}
int size(int v){ return -d[root(v)]; }
};
int main()
{
int n,m,q;
scanf(" %d %d %d", &n, &m, &q);
vector<pi> edge(m);
map<pi,int> edge_id;
rep(i,m)
{
int a,b;
scanf(" %d %d", &a, &b);
--a;
--b;
if(a>b) swap(a,b);
edge[i]=pi(a,b);
edge_id[edge[i]]=i;
}
vi destroy_id(q);
// 最後まで残り続ける橋
vector<bool> remain(m,true);
rep(i,q)
{
int c,d;
scanf(" %d %d", &c, &d);
--c;
--d;
if(c>d) swap(c,d);
destroy_id[i]=edge_id[pi(c,d)];
remain[destroy_id[i]]=false;
}
UF final_state(n), initial_state(n);
rep(i,m)
{
initial_state.unite(edge[i].fi, edge[i].se);
if(remain[i]) final_state.unite(edge[i].fi, edge[i].se);
}
// -2:undefined
vi ans(n,-2);
for(int i=1; i<n; ++i)
{
// 最初から到達不可能
if(initial_state.root(0) != initial_state.root(i)) ans[i]=0;
// 最後まで到達可能
if(final_state.root(0) == final_state.root(i)) ans[i]=-1;
}
// parallel binary search
// クエリをl番まで処理した時にはまだ0とiはつながっていて、r番まで処理した時には繋がっていない
vi l(n,0),r(n,q);
rep(times,18)
{
vector<vi> pos(q);
// 頂点iについて
for(int i=1; i<n; ++i)
{
// undefinedのみに注目
if(ans[i]==-2)
{
int mid = (l[i]+r[i])/2;
pos[mid].pb(i);
}
}
UF state(n);
// まず最終的な状態を再現
rep(i,m)
{
if(remain[i]) state.unite(edge[i].fi, edge[i].se);
}
// 後ろから見ていき、徐々に辺を追加していく
for(int i=q-1; i>=0; --i)
{
pi e=edge[destroy_id[i]];
state.unite(e.fi, e.se);
if(pos[i].size()>0)
{
//クエリ処理
for(const int &vnum:pos[i])
{
if(state.root(0) == state.root(vnum)) l[vnum]=i;
else r[vnum]=i;
}
}
}
}
for(int i=1; i<n; ++i) printf("%d\n", ans[i]==-2?r[i]:ans[i]);
return 0;
}