#include using namespace std; #define ALL(x) begin(x),end(x) #define rep(i,n) for(int i=0;i<(n);i++) #define debug(v) cout<<#v<<":";for(auto x:v){cout<bool chmax(T &a,const T &b){if(abool chmin(T &a,const T &b){if(b ostream &operator<<(ostream &os,const vector&v){ for(int i=0;i<(int)v.size();i++) os< istream &operator>>(istream &is,vector&v){ for(T &x:v)is>>x; return is; } struct LowLink{ const vector> &g; vector used,ord,low; vector articulation;// 関節点 vector> bridge;// 橋 LowLink(const vector> &g):g(g){} int dfs(int pre,int now,int k){ used[now]=1; ord[now]=k++; low[now]=ord[now]; bool is_articulation=false,multi_edge=false; int cnt=0; for(auto &to:g[now]){ if(to==pre and !multi_edge){ multi_edge=true; continue; } if(!used[to]){ cnt++; k=dfs(now,to,k); low[now]=min(low[now],low[to]); is_articulation|=(pre>=0 and low[to]>=ord[now]); if(ord[now]1); if(is_articulation) articulation.push_back(now); return k; } void build(){ used.assign(g.size(),0); ord.assign(g.size(),0); low.assign(g.size(),0); int k=0; for(int i=0;i<(int)g.size();i++)if(!used[i]) k=dfs(-1,i,k); } bool isBridge(int u,int v){ if(ord[u]>ord[v]) swap(u,v); return ord[u] comp; vector> tree,group; TwoEdgeConnectedComponents(const vector> &g):LL(g){} //点k の属する二重辺連結成分 int operator[](const int &k){ return comp[k]; } void dfs(int pre,int now,int &k){ if(pre>=0 and LL.ord[pre]>=LL.low[now]) comp[now]=comp[pre]; else comp[now]=k++; for(auto &to:LL.g[now]){ if(comp[to]==-1) dfs(now,to,k); } } void build(){ LL.build(); comp.assign(LL.g.size(),-1); int k=0; for(int i=0;i<(int)comp.size();i++){ if(comp[i]==-1) dfs(-1,i,k); } group.resize(k); for(int i=0;i<(int)LL.g.size();i++) group[comp[i]].push_back(i); tree.resize(k); for(auto &e:LL.bridge){ int u=comp[e.first],v=comp[e.second]; tree[u].push_back(v); tree[v].push_back(u); } } }; struct HLD{ vector> g; // u以下の部分木->[in[u],out[u]) vector sz,in,out,head,rev,par,dep; HLD(vector> g): g(g),sz(g.size()),in(g.size()),out(g.size()),head(g.size()),rev(g.size()),par(g.size()){} void build(){ sz.assign(g.size(),0); in.assign(g.size(),0); out.assign(g.size(),0); head.assign(g.size(),0); rev.assign(g.size(),0); par.assign(g.size(),0); dep.assign(g.size(),0); dfs_sz(-1,0,0); int t=0; dfs_hld(-1,0,t); } int la(int v,int k){ while(true){ int u=head[v]; if(in[v]-k>=in[u]) return rev[in[v]-k]; k-=in[v]-in[u]+1; v=par[u]; } } int lca(int u,int v){ for(;;v=par[head[v]]){ /* heavyな辺から先に訪問している 訪問順が遅い方を上げていけばlcaを超えない*/ if(in[u]>in[v]) swap(u,v); if(head[u]==head[v]) return u; } } int dis(int u,int v){ return dep[u]+dep[v]-2*dep[lca(u,v)]; } /* u-v のパスに関するクエリ ti: 元的な,ll付けるの忘れない q: パスの区間の求値関数,だいたいq(u,v)=seg.query(u,v) f: パスごとの結果をマージしていく関数 */ template E query(int u,int v,const E &ti,const Q &q,const F &f,bool edge=false){ E l=ti,r=ti; for(;;v=par[head[v]]){ if(in[u]>in[v]) swap(u,v),swap(l,r); if(head[u]==head[v]) break; l=f(q(in[head[v]],in[v]+1),l); } return f(f(q(in[u]+edge,in[v]+1),l),r); } template void add_path(int u,int v,const Q &q,bool edge=false){ for(;;v=par[head[v]]){ if(in[u]>in[v]) swap(u,v); if(head[u]==head[v]) break; q(in[head[v]],in[v]+1); } q(in[u]+edge,in[v]+1); } void dfs_sz(int pre,int now,int d){ dep[now]=d; par[now]=pre; sz[now]=1; if(g[now].size() and g[now][0]==pre) swap(g[now][0],g[now].back()); for(auto &to:g[now])if(to!=pre){ dfs_sz(now,to,d+1); sz[now]+=sz[to]; // 0がheavyな辺の先 if(sz[g[now][0]] struct SegmentTree{ using F=function; int sz; vector seg; const F f; const Monoid gen; SegmentTree(int n,const F f,const Monoid &gen):f(f),gen(gen){ sz=1; while(sz0;k--) seg[k]=f(seg[2*k],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],seg[2*k+1]); } // [a,b) Monoid query(int a,int b){ Monoid L=gen,R=gen; for(a+=sz,b+=sz;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]; } }; signed main(){ int n,m,q;cin>>n>>m>>q; vector> g(n); rep(i,m){ int u,v;cin>>u>>v;u--,v--; g[u].push_back(v); g[v].push_back(u); } TwoEdgeConnectedComponents tecc(g); tecc.build(); HLD hld(tecc.tree); hld.build(); SegmentTree> seg(n,[&](pair lhs,pair rhs){return max(lhs,rhs);},make_pair(0,0)); seg.build(); vector> ques(n); while(q--){ int t,u,v;cin>>t>>u>>v;u--; if(t==1){ int tid=tecc[u]; int id=hld.in[tid]; ques[id].push(v); seg.update(id,{ques[id].top(),id}); }else{ v--; auto res=hld.query(tecc[u],tecc[v],pair(0,0),[&](int lw,int hi){return seg.query(lw,hi);},[&](pair lhs,pair rhs){return max(lhs,rhs);}); if(res.first==0) cout<<-1<