#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define allof(obj) (obj).begin(), (obj).end() #define range(i, l, r) for(int i=l;i>1)|y_bit)) #define bit_kth(i, k) ((i >> k)&1) #define bit_highest(i) (i?63-__builtin_clzll(i):-1) #define bit_lowest(i) (i?__builtin_ctzll(i):-1) #define sleepms(t) std::this_thread::sleep_for(std::chrono::milliseconds(t)) using ll = long long; using ld = long double; using ul = uint64_t; using pi = std::pair; using pl = std::pair; using namespace std; template std::ostream &operator<<(std::ostream &dest, const std::pair &p){ dest << p.first << ' ' << p.second; return dest; } template std::ostream &operator<<(std::ostream &dest, const std::vector> &v){ int sz = v.size(); if(sz==0) return dest; for(int i=0;i std::ostream &operator<<(std::ostream &dest, const std::vector &v){ int sz = v.size(); if(sz==0) return dest; for(int i=0;i std::ostream &operator<<(std::ostream &dest, const std::array &v){ if(sz==0) return dest; for(int i=0;i std::ostream &operator<<(std::ostream &dest, const std::set &v){ for(auto itr=v.begin();itr!=v.end();){ dest << *itr; itr++; if(itr!=v.end()) dest << ' '; } return dest; } template std::ostream &operator<<(std::ostream &dest, const std::map &v){ for(auto itr=v.begin();itr!=v.end();){ dest << '(' << itr->first << ", " << itr->second << ')'; itr++; if(itr!=v.end()) dest << '\n'; } return dest; } std::ostream &operator<<(std::ostream &dest, __int128_t value) { std::ostream::sentry s(dest); if (s) { __uint128_t tmp = value < 0 ? -value : value; char buffer[128]; char *d = std::end(buffer); do { --d; *d = "0123456789"[tmp % 10]; tmp /= 10; } while (tmp != 0); if (value < 0) { --d; *d = '-'; } int len = std::end(buffer) - d; if (dest.rdbuf()->sputn(d, len) != len) { dest.setstate(std::ios_base::badbit); } } return dest; } template vector make_vec(size_t sz, T val){return std::vector(sz, val);} template auto make_vec(size_t sz, Tail ...tail){ return std::vector(tail...))>(sz, make_vec(tail...)); } template vector read_vec(size_t sz){ std::vector v(sz); for(int i=0;i<(int)sz;i++) std::cin >> v[i]; return v; } template auto read_vec(size_t sz, Tail ...tail){ auto v = std::vector(tail...))>(sz); for(int i=0;i<(int)sz;i++) v[i] = read_vec(tail...); return v; } long long max(long long a, int b){return std::max(a, (long long)b);} long long max(int a, long long b){return std::max((long long)a, b);} long long min(long long a, int b){return std::min(a, (long long)b);} long long min(int a, long long b){return std::min((long long)a, b);} long long modulo(long long a, long long m){a %= m; return a < 0 ? a + m : a;} template struct safe_vector : std::vector{ using std::vector::vector; T& operator [](size_t i){return this->at(i);} }; template struct safe_array : std::array{ using std::array::array; T& operator [](size_t i){return this->at(i);} }; ll ceil_div(ll x, ll y){ assert(y > 0); return (x + (x > 0 ? y - 1 : 0)) / y; } ll floor_div(ll x, ll y){ assert(y > 0); return (x + (x > 0 ? 0 : -y + 1)) / y; } void io_init(){ std::cin.tie(nullptr); std::ios::sync_with_stdio(false); } template struct toptree{ using tts = top_tree_structure; using HVal = typename tts::HVal; using LVal = typename tts::LVal; static constexpr auto id = tts::id; static constexpr auto to_light = tts::to_light; static constexpr auto merge_ll = tts::merge_light; static constexpr auto merge_hl = tts::merge_heavy_light; static constexpr auto merge_hh = tts::merge_heavy; struct node{ node *Hl, *Hr, *Hp; node *Lt, *Ll, *Lr, *Lp; int ALLsz, Lsz; bool flip; HVal val, ALLsum, ALLsumrev; LVal Lsum; node(HVal _val = id()): Hl(nullptr), Hr(nullptr), Hp(nullptr), Lt(nullptr), Ll(nullptr), Lr(nullptr), Lp(nullptr), ALLsz(1), Lsz(1), flip(false), val(_val), ALLsum(_val), ALLsumrev(_val), Lsum(to_light(_val)){} template bool is_root(){ if constexpr (is_heavy){ return !Hp || (Hp->Hl != this && Hp->Hr != this); }else{ return !Lp || (Lp->Ll != this && Lp->Lr != this); } } }; static node *make_node(HVal val){return new node(val);} toptree(){} private: template static void push_down(node *v){ if constexpr (is_heavy){ if(v->flip){ if(v->Hl) flip(v->Hl); if(v->Hr) flip(v->Hr); v->flip = false; } } } static void flip(node *v){ std::swap(v->Hl, v->Hr); std::swap(v->ALLsum, v->ALLsumrev); v->flip ^= 1; } template static void update(node *v){ if constexpr (is_heavy){ v->ALLsz = 1; v->ALLsum = v->ALLsumrev = v->val; HVal c = id(), crev = id(); if(v->Hl){ v->ALLsz += v->Hl->ALLsz; v->ALLsum = merge_hh(v->Hl->ALLsum, v->ALLsum); crev = v->Hl->ALLsumrev; } if(v->Hr){ v->ALLsz += v->Hr->ALLsz; v->ALLsumrev = merge_hh(v->Hr->ALLsumrev, v->ALLsumrev); c = v->Hr->ALLsum; } if(v->Lt){ v->ALLsz += v->Lt->Lsz; c = merge_hl(c, v->Lt->Lsum); crev = merge_hl(crev, v->Lt->Lsum); } v->ALLsum = merge_hh(v->ALLsum, c); v->ALLsumrev = merge_hh(v->ALLsumrev, crev); }else{ v->Lsum = to_light(v->ALLsum); v->Lsz = v->ALLsz; if(v->Ll){ v->Lsz += v->Ll->Lsz; v->Lsum = merge_ll(v->Lsum, v->Ll->Lsum); } if(v->Lr){ v->Lsz += v->Lr->Lsz; v->Lsum = merge_ll(v->Lsum, v->Lr->Lsum); } } } template static void rotate_right(node *v){ if constexpr (is_heavy){ node *p = v->Hp, *pp = p->Hp; if((p->Hl = v->Hr)) v->Hr->Hp = p; v->Hr = p, p->Hp = v; update<1>(p), update<1>(v); if((v->Hp = pp)){ if(pp->Hl == p) pp->Hl = v; if(pp->Hr == p) pp->Hr = v; update<1>(pp); } }else{ node *p = v->Lp, *pp = p->Lp; if((p->Ll = v->Lr)) v->Lr->Lp = p; v->Lr = p, p->Lp = v; update<0>(p), update<0>(v); if((v->Lp = pp)){ if(pp->Ll == p) pp->Ll = v; if(pp->Lr == p) pp->Lr = v; update<0>(pp); } } } template static void rotate_left(node *v){ if constexpr (is_heavy){ node *p = v->Hp, *pp = p->Hp; if((p->Hr = v->Hl)) v->Hl->Hp = p; v->Hl = p, p->Hp = v; update<1>(p), update<1>(v); if((v->Hp = pp)){ if(pp->Hl == p) pp->Hl = v; if(pp->Hr == p) pp->Hr = v; update<1>(pp); } }else{ node *p = v->Lp, *pp = p->Lp; if((p->Lr = v->Ll)) v->Ll->Lp = p; v->Ll = p, p->Lp = v; update<0>(p), update<0>(v); if((v->Lp = pp)){ if(pp->Ll == p) pp->Ll = v; if(pp->Lr == p) pp->Lr = v; update<0>(pp); } } } template static void splay(node *v){ if constexpr (is_heavy){ node *u = nullptr; push_down<1>(v); while(!v->template is_root<1>()){ node *p = v->Hp; if(p->template is_root<1>()){ u = p; push_down<1>(p), push_down<1>(v); if(p->Hl == v) rotate_right<1>(v); else rotate_left<1>(v); }else{ node *pp = p->Hp; if(pp->template is_root<1>()) u = pp; push_down<1>(pp), push_down<1>(p), push_down<1>(v); if(pp->Hl == p){ if(p->Hl == v) rotate_right<1>(p); else rotate_left<1>(v); rotate_right<1>(v); }else{ if(p->Hr == v) rotate_left<1>(p); else rotate_right<1>(v); rotate_left<1>(v); } } } if(u){ node *Ll = u->Ll, *Lr = u->Lr, *Lp = u->Lp; u->Ll = u->Lr = u->Lp = nullptr; if((v->Ll = Ll)) Ll->Lp = v; if((v->Lr = Lr)) Lr->Lp = v; if((v->Lp = Lp)){ if(Lp->Ll == u) Lp->Ll = v; if(Lp->Lr == u) Lp->Lr = v; if(Lp->Lt == u) Lp->Lt = v; } } }else{ push_down<0>(v); while(!v->template is_root<0>()){ node *p = v->Lp; if(p->template is_root<0>()){ push_down<0>(p), push_down<0>(v); if(p->Ll == v) rotate_right<0>(v); else rotate_left<0>(v); }else{ node *pp = p->Lp; push_down<0>(pp), push_down<0>(p), push_down<0>(v); if(pp->Ll == p){ if(p->Ll == v) rotate_right<0>(p); else rotate_left<0>(v); rotate_right<0>(v); }else{ if(p->Lr == v) rotate_left<0>(p); else rotate_right<0>(v); rotate_left<0>(v); } } } } } static void insert_light(node *p, node *c){ push_down<0>(p); push_down<0>(c); if((c->Ll = p->Lt)) p->Lt->Lp = c; update<0>(c); p->Lt = c; c->Lp = p; update<1>(p); } static void erase_light(node *p, node *c){ splay<0>(c); node *l = c->Ll, *r = c->Lr; c->Ll = c->Lr = c->Lp = nullptr; if(l && r){ l->Lp = r->Lp = nullptr; while(l->Lr) l = l->Lr; splay<0>(l); l->Lr = r; r->Lp = l; update<0>(l); }else if(r) l = r; if(l) l->Lp = p; p->Lt = l; update<1>(p); } static void swap_light(node *p, node *a, node *b){ push_down<0>(a); splay<0>(b); node *l = b->Ll, *r = b->Lr; b->Ll = b->Lr = b->Lp = nullptr; if((a->Ll = l)) l->Lp = a; if((a->Lr = r)) r->Lp = a; if((a->Lp = p)) p->Lt = a; update<0>(a); update<0>(b); } static node *expose(node *v){ node *c = nullptr; for(node *u = v; u; u = u->Hp){ splay<1>(u); if(c && u->Hr) swap_light(u, u->Hr, c); else if(c) erase_light(u, c); else if(u->Hr) insert_light(u, u->Hr); u->Hr = c; update<1>(u); c = u; } splay<1>(v); return c; } public: // vを根にする static node *evert(node *v){ expose(v); flip(v); push_down<1>(v); return v; } // 非連結であることが保証されている場合 static void _link(node *p, node *c){ evert(c); expose(p); c->Hp = p; p->Hr = c; update<1>(p); } // 辺(a, b)があることが保証されている場合 static bool _cut(node *u, node *v){ evert(u); return cut_from_parent(v); } // 連結なことが保証されている場合 static node *_lca(node *u, node *v){ expose(u); return expose(v); } // cの親との辺を切る, false: 辺を切れなかった static bool cut_from_parent(node *c){ expose(c); node *p = c->Hl; if(p == nullptr) return false; c->Hl = p->Hp = nullptr; update<1>(c); return true; } static node *get_root(node *v){ expose(v); while(v->Hl){ push_down<1>(v); v = v->Hl; } splay<1>(v); return v; } // 同じ連結成分か static bool is_same(node *u, node *v){ if(!u || !v) return false; return get_root(u) == get_root(v); } static node *lca(node *u, node *v){ if(!is_same(u, v)) return nullptr; return _lca(u, v); } static int size_subtree(node *v){ expose(v); return 1 + (v->Lt ? v->Lt->Lsz : 0); } static void set(node *v, HVal x){ expose(v); v->val = x; update<1>(v); } static HVal get(node *v){ expose(v); return v->val; } static LVal query_subtree(node *v){ expose(v); if(!v->Hl){ return to_light(v->ALLsum); }else{ HVal r = id(); if(v->Lt) r = merge_hl(r, v->Lt->Lsum); return to_light(merge_hh(v->val, r)); } } // evert(v) -> query_subtree(v) と同じ(実際にはevertしない) static LVal query_rerooting(node *v){ expose(v); if(!v->Hl){ return to_light(v->ALLsum); }else{ LVal parrev = to_light(v->Hl->ALLsumrev); if(v->Lt) parrev = merge_ll(parrev, v->Lt->Lsum); return to_light(merge_hl(v->val, parrev)); } } static node *aaa(node *v, int one){ expose(v); while(true){ HVal subsum = id(); node *u = nullptr; while(v){ push_down<1>(v); HVal x = (v->Hr ? v->Hr->ALLsum : id()); x = merge_hh(x, subsum); if(v->Lt) x = merge_hl(x, v->Lt->Lsum); x = merge_hh(v->val, x); if(one <= 2 * x.add){ // lに動いてはいけない u = v; v = v->Hr; }else{ v = v->Hl; subsum = x; } } assert(u); v = u; if(!v->Lt || 2 * v->Lt->Lsum.addmax <= one){ expose(v); return v; } v = v->Lt; while(true){ node *u = v; if(v->Ll && 2 * v->Ll->Lsum.addmax >= one) u = v->Ll; if(v->Lr && 2 * v->Lr->Lsum.addmax >= one) u = v->Lr; if(u == v) break; v = u; } } } }; template struct distance_sum{ struct F{ T distsum, add, len; }; struct G{ T distsum, add, addmax; }; using HVal = F; using LVal = G; static constexpr HVal id(){ return {0, 0, 0}; } static constexpr LVal to_light(const HVal &v){ return {v.distsum, v.add, v.add}; } static constexpr HVal merge_heavy_light(const HVal &a, const LVal &b){ return {a.distsum + b.distsum, a.add + b.add, a.len}; } static constexpr HVal merge_heavy(const HVal &p, const HVal &c){ return {p.distsum + c.distsum + p.len * c.add, p.add + c.add, p.len + c.len}; } static constexpr LVal merge_light(const LVal &a, const LVal &b){ return {a.distsum + b.distsum, a.add + b.add, std::max(a.addmax, b.addmax)}; } }; int main(){ io_init(); int n, q; std::cin >> n >> q; using tt = toptree>; using node = typename tt::node; vector v(n); range(i, 0, n) v[i] = tt::make_node({0, 1, 0}); map, node*> E; map> Erev; ll S = 0; range(i, 0, q){ int t; std::cin >> t; if(t == 1){ int a, b, c; std::cin >> a >> b >> c; a = (a - 1 + S) % n; b = (b - 1 + S) % n; if(a > b) swap(a, b); node *e = tt::make_node({0, 0, c}); tt::_link(v[a], e); tt::_link(v[b], e); E[{a, b}] = e; Erev[e] = {a, b}; }else if(t == 2){ int a, b; std::cin >> a >> b; a = (a - 1 + S) % n; b = (b - 1 + S) % n; if(a > b) swap(a, b); auto itr = E.find({a, b}); node *e = itr->second; tt::_cut(v[a], e); tt::_cut(v[b], e); }else{ int a; std::cin >> a; a = (a - 1 + S) % n; int newval = !v[a]->val.add; tt::set(v[a], {0, newval, 0}); int one = v[a]->ALLsum.add; auto u = tt::aaa(v[a], one); ll ans = 0; if(u->val.len == 0){ ans = tt::query_rerooting(u).distsum; }else{ auto [c, d] = Erev[u]; ans = min(tt::query_rerooting(v[c]).distsum, tt::query_rerooting(v[d]).distsum); } std::cout << ans << '\n'; S = (S + ans) % n; } } }