#include using namespace std; using ll=long long; using int64=ll; long long infll=1e18; long long inf=1e15; long long infll2=2e18; template< typename SUM, typename KEY > struct LinkCutTreeSubtree { struct Node { Node *l, *r, *p; KEY key; SUM sum; bool rev; int sz; bool is_root() const { return !p || (p->l != this && p->r != this); } Node(const KEY &key, const SUM &sum) : key(key), sum(sum), rev(false), sz(1), l(nullptr), r(nullptr), p(nullptr) {} }; const SUM ident; LinkCutTreeSubtree(const SUM &ident) : ident(ident) {} Node *make_node(const KEY &key) { auto ret = new Node(key, ident); update(ret); return ret; } Node *set_key(Node *t, const KEY &key) { expose(t); t->key = key; update(t); return t; } void toggle(Node *t) { swap(t->l, t->r); t->sum.toggle(); t->rev ^= true; } void push(Node *t) { if(t->rev) { if(t->l) toggle(t->l); if(t->r) toggle(t->r); t->rev = false; } } void update(Node *t) { t->sz = 1; if(t->l) t->sz += t->l->sz; if(t->r) t->sz += t->r->sz; t->sum.merge(t->key, t->l ? t->l->sum : ident, t->r ? t->r->sum : ident); } void rotr(Node *t) { auto *x = t->p, *y = x->p; if((x->l = t->r)) t->r->p = x; t->r = x, x->p = t; update(x), update(t); if((t->p = y)) { if(y->l == x) y->l = t; if(y->r == x) y->r = t; update(y); } } void rotl(Node *t) { auto *x = t->p, *y = x->p; if((x->r = t->l)) t->l->p = x; t->l = x, x->p = t; update(x), update(t); if((t->p = y)) { if(y->l == x) y->l = t; if(y->r == x) y->r = t; update(y); } } void splay(Node *t) { push(t); while(!t->is_root()) { auto *q = t->p; if(q->is_root()) { push(q), push(t); if(q->l == t) rotr(t); else rotl(t); } else { auto *r = q->p; push(r), push(q), push(t); if(r->l == q) { if(q->l == t) rotr(q), rotr(t); else rotl(t), rotr(t); } else { if(q->r == t) rotl(q), rotl(t); else rotr(t), rotl(t); } } } } Node *expose(Node *t) { Node *rp = nullptr; for(auto *cur = t; cur; cur = cur->p) { splay(cur); if(cur->r) cur->sum.add(cur->r->sum); cur->r = rp; if(cur->r) cur->sum.erase(cur->r->sum); update(cur); rp = cur; } splay(t); return rp; } void link(Node *child, Node *parent) { expose(child); expose(parent); child->p = parent; parent->r = child; } void cut(Node *child) { expose(child); auto *parent = child->l; child->l = nullptr; parent->p = nullptr; update(child); } void evert(Node *t) { expose(t); toggle(t); push(t); } Node *lca(Node *u, Node *v) { if(get_root(u) != get_root(v)) return nullptr; expose(u); return expose(v); } Node *get_kth(Node *x, int k) { expose(x); while(x) { push(x); if(x->r && x->r->sz > k) { x = x->r; } else { if(x->r) k -= x->r->sz; if(k == 0) return x; k -= 1; x = x->l; } } return nullptr; } Node *get_root(Node *x) { expose(x); while(x->l) { push(x); x = x->l; } return x; } }; struct PQ { priority_queue< int64 > in, out; inline int64 top() { if(!in.empty()) return in.top(); return -infll; } inline void insert(int64 k) { if(k < -inf) return; in.emplace(k); } inline void erase(int64 k) { if(k < -inf) return; out.emplace(k); while(out.size() && in.top() == out.top()) { in.pop(); out.pop(); } } inline int64 top2() { if(in.empty()) return -infll; int64 top = in.top(); erase(top); int64 top2 = this->top(); in.push(top); return top2; } }; template struct LinkCutTree{ using F = function; using G = function; using H = function; using S = function; struct Node{ Node *p,*l,*r; int idx; T key, sum; OT lazy; int sz; bool rev; bool is_root(){ return !p || (p->l != this && p->r != this); } Node(int idx, const T &key,const OT &om): idx(idx),key(key),sum(key),lazy(om),sz(1), l(nullptr),r(nullptr),p(nullptr),rev(false){} }; const T M1; const OT OM0; const F f; const G g; const H h; const S s; vectorver; LinkCutTree(int n): LinkCutTree(n,[&](T x,T y){return x;},[&](T x){return x;},T()){} LinkCutTree(int n,const F &f,const S &s,const T M1): LinkCutTree(n,f,G(),H(),s,M1,OT()){} LinkCutTree(int n,const F &f,const G &g,const H &h, const S &s,const T M1,const OT OM0) :f(f),g(g),h(h),s(s),ver(n),M1(M1),OM0(OM0){} void update(Node *t){ t->sz = 1; t->sum = t->key; if(t->l)t->sz += t->l->sz, t->sum = f(t->l->sum, t->sum); if(t->r)t->sz += t->r->sz, t->sum = f(t->sum, t->r->sum); } void rotr(Node *t){ Node *x = t->p, *y = x->p; if((x->l = t->r))t->r->p = x; t->r = x, x->p = t; update(x),update(t); if((t->p = y)){ if(y->l == x)y->l = t; if(y->r == x)y->r = t; update(y); } } void rotl(Node *t){ Node *x =t->p, *y = x->p; if((x->r = t->l))t->l->p = x; t->l = x, x->p = t; update(x),update(t); if((t->p = y)){ if(y->l == x)y->l = t; if(y->r == x)y->r = t; update(y); } } void splay(Node *t){ push(t); while(!t->is_root()){ Node *q = t->p; if(q->is_root()){ push(q), push(t); if(q->l == t)rotr(t); else rotl(t); } else{ Node *r = q->p; push(r), push(q), push(t); if(r->l == q){ if(q->l == t)rotr(q), rotr(t); else rotl(t), rotr(t); } else{ if(q->r == t)rotl(q), rotl(t); else rotr(t), rotl(t); } } } } Node *expose(Node *t){ Node *rp = nullptr; Node *cur = t; while(cur){ splay(cur); cur->r = rp; update(cur); rp = cur; cur = cur->p; } splay(t); return rp; } void link(Node *child, Node *parent){ expose(child); expose(parent); child->p = parent; parent->r = child; update(parent); } void cut(Node *child){ expose(child); Node *parent = child->l; child->l = nullptr; parent->p = nullptr; update(child); } void toggle(Node *t){ assert(t); swap(t->l,t->r); t->sum = s(t->sum); t->rev^=true; } void evert(Node *t){ expose(t); toggle(t); push(t); } Node *make_node(int idx,T v = T()){ return new Node(idx, v, OM0); } void push(Node *t){ if(t->lazy != OM0){ if(t->l)propagate(t->l, t->lazy); if(t->r)propagate(t->r, t->lazy); t->lazy = OM0; } if(t->rev){ if(t->l)toggle(t->l); if(t->r)toggle(t->r); t->rev=false; } } Node *lca(Node *u, Node *v){ expose(u); return expose(v); } void propagate(Node *t, const OT x){ t->lazy = h(t->lazy, x); t->key = g(t->key, x); t->sum = g(t->sum, x); } //ここから操作 void add_vertex(int idx,T v = T()){//頂点idxの追加 ver[idx] = make_node(idx, v); } void evert(int x){//根をxに evert(ver[x]); } void add_edge(int x,int y){//(x->y)の追加 evert(y); link(ver[y],ver[x]); } void cut_edge(int x,int y){ evert(x); cut(ver[y]); } T val(int x){ return ver[x]->key; } T val_path(int x){//根~xのパスクエリ expose(ver[x]); return ver[x]->sum; } T val_path(int x,int y){//x->yのパスクエリ evert(x); return val_path(y); } void update(int x,T v){//頂点xの値をvに expose(ver[x]); ver[x]->key = v; update(ver[x]); } void update_path(int x,const OT v){//根~xのパス更新 expose(ver[x]); propagate(ver[x], v); push(ver[x]); } void update_path(int x,int y,const OT v){//x~yのパス更新 evert(x); update_path(y,v); } int lca(int x,int y){ return lca(ver[x], ver[y])->idx; } bool connected(int x,int y){//頂点xとyが連結か? if(x==y)return true; expose(ver[x]); expose(ver[y]); return bool(ver[x]->p); } int parent(int x,int r){//根がrの時のxの親 存在しない場合は-1 evert(r); expose(ver[x]); Node *t = ver[x]->l; if(!t)return -1; push(t); while(t->r){ t = t->r; push(t); } return t->idx; } int root(int x){ expose(ver[x]); Node *t = ver[x]; push(t); while(t->l){ t = t->l; push(t); } return t->idx; } }; int main() { int N; cin>>N; using Key = int64; struct Sum { int64 all; int64 p_len, c_len; int64 diameter; PQ md1, md2; Sum() : all(0), p_len(-infll), c_len(-infll), diameter(-infll) {} void toggle() { swap(p_len, c_len); } void merge(Key key, const Sum &parent, const Sum &child) { bool sw = false; if(key == infll) { sw = true; key = 0; } all = parent.all + key + child.all; int64 top = md1.top(); p_len = max(child.p_len, max(top, parent.p_len) + key + child.all); c_len = max(parent.c_len, max(top, child.c_len) + key + parent.all); diameter = max({parent.diameter, child.diameter, top + key + md1.top2(), md2.top()}); diameter = max({diameter, parent.p_len + key + max(child.c_len, top), child.c_len + key + top}); if(sw) { p_len = max(p_len, key + child.all); c_len = max(c_len, key + parent.all); diameter = max(diameter, max({parent.p_len, child.c_len, top, 0LL}) + key); } if(p_len < -infll2) p_len = -infll; if(c_len < -infll2) c_len = -infll; if(diameter < -infll2) diameter = -infll; } void add(const Sum &ch) { md1.insert(ch.c_len); md2.insert(ch.diameter); } void erase(const Sum &ch) { md1.erase(ch.c_len); md2.erase(ch.diameter); } } e; using LCT = LinkCutTreeSubtree< Sum, Key >; LCT lct(e); vector< LCT::Node * > vv(N), ee(N); for(int i = 0; i < N; i++) { vv[i] = lct.make_node(infll); } auto ff=[&](ll x,ll y){return x+y;}; auto fs=[&](ll x){return x;}; LinkCutTree lce(2*N,ff,fs,0LL); for(int i=0;i<2*N;i++)lce.add_vertex(i,0); ll n=N; ll x0,q;cin>>x0>>q; int cnt=0; while(q--){ ll t;cin>>t; if(t==1){ ll v,w;cin>>v>>w; lce.update(cnt+n,w); lce.add_edge(cnt+n,v); lce.add_edge(cnt+n,x0); ee[cnt]=lct.make_node(w); lct.link(vv[v],ee[cnt]); lct.link(ee[cnt],vv[x0]); cnt++; } if(t==2){ int u,v;cin>>u>>v; if(lce.connected(u,v)){ ll d=lce.val_path(u,v); cout<>v; lct.expose(vv[v]); cout<<(vv[v]->sum.diameter)<>ad; x0+=ad; x0%=n; } //cout<<"x:"<