結果
問題 | No.529 帰省ラッシュ |
ユーザー | ei1821 |
提出日時 | 2020-08-08 12:18:36 |
言語 | C++14 (gcc 12.3.0 + boost 1.83.0) |
結果 |
AC
|
実行時間 | 632 ms / 4,500 ms |
コード長 | 9,494 bytes |
コンパイル時間 | 2,860 ms |
コンパイル使用メモリ | 202,000 KB |
実行使用メモリ | 60,912 KB |
最終ジャッジ日時 | 2024-10-01 12:57:05 |
合計ジャッジ時間 | 11,934 ms |
ジャッジサーバーID (参考情報) |
judge2 / judge1 |
(要ログイン)
テストケース
テストケース表示入力 | 結果 | 実行時間 実行使用メモリ |
---|---|---|
testcase_00 | AC | 2 ms
5,248 KB |
testcase_01 | AC | 1 ms
5,248 KB |
testcase_02 | AC | 2 ms
5,248 KB |
testcase_03 | AC | 2 ms
5,248 KB |
testcase_04 | AC | 8 ms
5,248 KB |
testcase_05 | AC | 7 ms
5,248 KB |
testcase_06 | AC | 7 ms
5,248 KB |
testcase_07 | AC | 7 ms
5,248 KB |
testcase_08 | AC | 441 ms
26,256 KB |
testcase_09 | AC | 430 ms
26,976 KB |
testcase_10 | AC | 472 ms
37,668 KB |
testcase_11 | AC | 474 ms
38,184 KB |
testcase_12 | AC | 387 ms
27,520 KB |
testcase_13 | AC | 355 ms
60,912 KB |
testcase_14 | AC | 436 ms
32,084 KB |
testcase_15 | AC | 632 ms
43,788 KB |
testcase_16 | AC | 567 ms
43,792 KB |
testcase_17 | AC | 572 ms
57,448 KB |
testcase_18 | AC | 569 ms
57,952 KB |
testcase_19 | AC | 564 ms
53,996 KB |
ソースコード
#include <bits/stdc++.h> #pragma GCD target ("arch=skylake-avx512") using namespace std; #define __ <<" "<< #define ___ <<" " #define bash push_back #define ALL(x) x.begin(),x.end() //#define int long long using Int = int; using ll = long long; using pii = pair<int, int>; constexpr int INF = 0x3f3f3f3f; constexpr long long LINF = 0x3f3f3f3f3f3f3f3fLL; constexpr int SMOD = 1000000007; constexpr int NMOD = 998244353; constexpr int dx[]={1,0,-1,0,1,1,-1,-1}; constexpr int dy[]={0,-1,0,1,-1,1,-1,1}; inline bool inside(int x,int y,int w,int h){return (x>=0 && y>=0 && x<w && y<h);} template<class T>bool chmax(T &a, const T&b){if(a<b)return(a=b,1);return 0;} template<class T>bool chmin(T &a, const T&b){if(b<a)return(a=b,1);return 0;} class HLD { private: void dfs_sz(int v) { for(int &u:G[v]) if(u==par[v]) swap(u,G[v].back()); if(~par[v]) G[v].pop_back(); for(int &u:G[v]){ par[u]=v; dep[u]=dep[v]+1; dfs_sz(u); sub[v]+=sub[u]; if(sub[u]>sub[G[v][0]]) swap(u,G[v][0]); } } void dfs_hld(int v,int c,int &pos) { vid[v]=pos++; inv[vid[v]]=v; type[v]=c; for(int u:G[v]){ if(u==par[v]) continue; head[u]=(u==G[v][0]?head[v]:u); dfs_hld(u,c,pos); } } public: vector< vector<int> > G; vector<int> vid, head, sub, par, dep, inv, type; HLD(int n): G(n),vid(n,-1),head(n),sub(n,1), par(n,-1),dep(n,0),inv(n),type(n){} // u <--> v void add_edge(int u,int v) { G[u].emplace_back(v); G[v].emplace_back(u); } void build(vector<int> rs={0}) { int c=0,pos=0; for(int r:rs){ dfs_sz(r); head[r]=r; dfs_hld(r,c++,pos); } } int lca(int u,int v){ while(1){ if(vid[u]>vid[v]) swap(u,v); if(head[u]==head[v]) return u; v=par[head[v]]; } } int distance(int u,int v){ return dep[u]+dep[v]-2*dep[lca(u,v)]; } // for_each(vertex) // [l, r) <- attention!! // 頂点属性のクエリ用 template<typename F> void for_each(int u, int v, const F& f) { while(1){ if(vid[u]>vid[v]) swap(u,v); f(max(vid[head[v]],vid[u]),vid[v]+1); if(head[u]!=head[v]) v=par[head[v]]; else break; } } template<typename T,typename Q,typename F> T for_each(int u,int v,T ti,const Q &q,const F &f){ T l=ti,r=ti; while(1){ if(vid[u]>vid[v]){ swap(u,v); swap(l,r); } l=f(l,q(max(vid[head[v]],vid[u]),vid[v]+1)); if(head[u]!=head[v]) v=par[head[v]]; else break; } return f(l,r); } // for_each(edge) // [l, r) <- attention!! template<typename F> void for_each_edge(int u, int v,const F& f) { while(1){ if(vid[u]>vid[v]) swap(u,v); if(head[u]!=head[v]){ f(vid[head[v]],vid[v]+1); v=par[head[v]]; }else{ if(u!=v) f(vid[u]+1,vid[v]+1); break; } } } }; template< typename Monoid > struct SegmentTree { using F = function< Monoid(Monoid, Monoid) >; int sz; vector< Monoid > seg; const F f; const Monoid M1; SegmentTree(int n, const Monoid &M1, const F f) : f(f), M1(M1) { sz = 1; while(sz < n) sz <<= 1; seg.assign(2 * sz, M1); } void set(int k, const Monoid &x) { seg[k + sz] = x; } void build() { for(int k = sz - 1; k > 0; k--) { seg[k] = f(seg[2 * k + 0], seg[2 * k + 1]); } } void update(int k, const Monoid &x) { k += sz; seg[k] = x; while(k >>= 1) { seg[k] = f(seg[2 * k + 0], seg[2 * k + 1]); } } Monoid query(int a, int b) { Monoid L = M1, R = M1; for(a += sz, b += sz; a < b; a >>= 1, b >>= 1) { if(a & 1) L = f(L, seg[a++]); if(b & 1) R = f(seg[--b], R); } return f(L, R); } Monoid operator[](const int &k) const { return seg[k + sz]; } }; struct LowLink{ int n,pos; vector<int> ord,low,par,blg,num; vector<vector<int> > G,C,T; vector<vector<pair<int, int> > > E; vector<int> ap; vector<pair<int, int> > bs,cand; LowLink(int n):n(n),pos(0),ord(n,-1),low(n), par(n,-1),blg(n,-1),num(n,1),G(n){} // ord: DFS順のナンバリング // low: dfs木の葉方向の辺を0回以上, 後退辺を高々1回通って到達可能なordの最小値 // ある辺(u, v)が橋であるとき、ord[u] < low[v]を満たす // par: 根付き木の親 // blg[v]: 頂点vが属する成分の番号 // num[v]: 頂点vを根とする部分木のサイズ // G: 与えられる生のグラフ // C[id]: 成分idに属する頂点のリスト // blg と C は相互関係 // T[v]: 成分(v, T[v][i]) を結ぶ辺 // 分解後の木となる // E: DFS木の辺のリスト E[i][j]の(first, second)は辺だけど E[i]が何を表すかはわからん // ap: 関節点のリスト // bs: 橋のリスト 辺(first, second) は橋である // cand: もしかしたら適当利用なやつで考慮しなくてもいいかもしれない // public void add_edge(int u,int v){ G[u].emplace_back(v); G[v].emplace_back(u); } // bool is_bridge(int u,int v){ if(ord[u]>ord[v]) swap(u,v); return ord[u]<low[v]; } void dfs(int v){ ord[v]=low[v]=pos++; int dup=0; for(int u:G[v]){ if(u==par[v]){ if(dup) low[v]=min(low[v],ord[u]); //二重辺がある dup=1; continue; } if(ord[u]<ord[v]) // vを根とした部分木の子(u, x)同士に辺があるときの辺(v, u) みたいなのを除くとき 根から後退辺を考えないようにしてる(?) cand.emplace_back(min(u,v),max(u,v)); if(~ord[u]){ low[v]=min(low[v],ord[u]); continue; } par[u]=v; dfs(u); num[v]+=num[u]; low[v]=min(low[v],low[u]); if(is_bridge(u,v)) bs.emplace_back(u,v); if(low[u]>=ord[v]){ E.emplace_back(); while(1){ auto e=cand.back(); cand.pop_back(); E.back().emplace_back(e); if(make_pair(min(u,v),max(u,v))==e) break; } } } } // ナンバリング void fill_component(int v){ C[blg[v]].emplace_back(v); for(int u:G[v]){ if(~blg[u]||is_bridge(u,v)) continue; blg[u]=blg[v]; fill_component(u); } } // 成分ごとにナンバリング void add_component(int v,int &k){ if(~blg[v]) return; blg[v]=k++; C.emplace_back(); fill_component(v); } // public int build(){ for(int i=0;i<n;i++) if(ord[i]<0) dfs(i); vector<int> cnt(n,0); for(int i=0;i<n;i++){ int p=par[i]; if(p<0) continue; if(par[p]<0) cnt[p]++; // 親が根の時カウント else if(ord[p]<=low[i]) ap.emplace_back(p); } for(int i=0;i<n;i++) if(cnt[i]>1) ap.emplace_back(i); //次数が1を超過 -> 関節点 sort(ap.begin(),ap.end()); ap.erase(unique(ap.begin(),ap.end()),ap.end()); int k=0; for(int i=0;i<n;i++) add_component(i,k); T.assign(k,vector<int>()); for(auto e:bs){ int u=blg[e.first],v=blg[e.second]; T[u].emplace_back(v); T[v].emplace_back(u); } return k; } }; bool visit[101010]; void dfs(vector<vector<int>>&e, int v, HLD&hld) { for(auto&&u:e[v]) { if(!visit[u]) { visit[u] = true; hld.add_edge(v, u); dfs(e, u, hld); } } } signed main() { int n, m, q; cin >> n >> m >> q; LowLink low(n); int a, b, c; for(int i = 0; i < m; i++) { cin >> a >> b; low.add_edge(a-1, b-1); } int after_n = low.build(); HLD hld(after_n); SegmentTree<pii> seg(after_n, pii(), [](pii a, pii b){return max(a, b);}); for(int i = 0; i < after_n; i++) { seg.set(i, pii(0, i + 1)); } visit[0] = true; dfs(low.T, 0, hld); hld.build(); vector<priority_queue<int>> pque(after_n); for(int i = 0; i < q; i++) { cin >> a >> b >> c; if(a == 1) { b = hld.vid[low.blg[b-1]]; pque[b].push(c); seg.update(b, pii(pque[b].top(), b+1)); } else { b = low.blg[b-1]; c = low.blg[c-1]; pii maxv; hld.for_each(b, c, [&](int l, int r){chmax(maxv, seg.query(l, r));}); if(!maxv.first) { cout << -1 << endl; } else { cout << maxv.first << endl; int nex = 0; b = maxv.second ; pque[b-1].pop(); if(!pque[b-1].empty()) nex = pque[b-1].top(); seg.update(b - 1, pii(nex, b)); } } } return 0; }