#include #include #include #include #include using namespace std; struct Node{ Node(int weight_ = 1, int len_ = 0) { left = right = parent = nullptr; weight[0] = weight_; weight[1] = len_; size[0] = weight[0]; size[1] = weight[1]; hSize = 0; sum[0] = sum[1] = hSum = 0; reverse = false; } ~Node() { makeRoot(); if (right) right->parent = nullptr; for (auto &p : hNode) p.second->parent = nullptr; } Node *left, *right, *parent; long long weight[2], size[2], hSize, sum[2], hSum; bool reverse; set > hNode; // loser. bool isRoot(); void propagate(); void update(); void rotate(); void splay(); Node* access(); void hidePath(); void chainPath(Node *node); void makeRoot(); void link(Node *node); void cut(); void changeWeight(int weight); Node* findCenter(); }; struct LinkCutTree { LinkCutTree(){} LinkCutTree(int size) { nodeList.resize(size); for (int i=0;i nodeList; void addNode(int weight = 1, int len = 0) { nodeList.emplace_back(new Node(weight, len)); } Node* getNode(int i) { if (0 <= i && i < nodeList.size()) return nodeList[i]; return nullptr; } }; bool Node::isRoot() { return this == nullptr || parent == nullptr || (parent->left != this && parent->right != this); } void Node::propagate() { if (reverse){ swap(left, right); swap(sum[0],sum[1]); if (left) left->reverse = !left->reverse; if (right) right->reverse = !right->reverse; reverse = false; } } void Node::update() { size[0] = weight[0] + hSize; size[1] = weight[1]; sum[0] = sum[1] = hSum; long long psum[2] = {size[0],size[0]}, qsum[2] = {size[1],size[1]}; if (left){ size[0] += left->size[0]; size[1] += left->size[1]; psum[1] += left->size[0]; qsum[0] += left->size[1]; } if (right){ size[0] += right->size[0]; size[1] += right->size[1]; psum[0] += right->size[0]; qsum[1] += right->size[1]; } for (int k=0;k<2;k++){ if (left) sum[k] += left->sum[k^left->reverse]; if (right) sum[k] += right->sum[k^right->reverse]; sum[k] += psum[k] * qsum[k]; } } void Node::rotate() { if (isRoot()) return; Node *up = parent; up->propagate(); propagate(); Node *jump = up->parent; up->parent = this; Node *down = nullptr; if (up->left == this){ up->left = down = right; right = up; } else{ up->right = down = left; left = up; } if (down) down->parent = up; parent = jump; if (jump){ int sz = up->size[0]; auto I = jump->hNode.find({sz, up}); if (I != jump->hNode.end()){ jump->hNode.erase(I); jump->hNode.insert({sz, this}); } else if (jump->left == up) jump->left = this; else if (jump->right == up) jump->right = this; } up->update(); update(); } void Node::splay() { propagate(); while (!isRoot()){ Node *up = parent; if (!up->isRoot()){ Node *jump = up->parent; if ((this == up->left) ^ (up == jump->left)) rotate(); else up->rotate(); } rotate(); } } Node* Node::access() { hidePath(); Node* last = this; while (parent){ last = parent; parent->chainPath(this); splay(); } return last; } void Node::hidePath() { splay(); if (right && right->parent == this){ hSize += right->size[0]; hSum += right->sum[right->reverse]; hNode.insert({right->size[0], right}); right = nullptr; update(); } } void Node::chainPath(Node *node) { hidePath(); if (node && node->parent == this && left != node){ right = node; hSize -= right->size[0]; hSum -= right->sum[right->reverse]; hNode.erase({right->size[0], right}); update(); } } void Node::makeRoot() { access(); reverse = !reverse; propagate(); } void Node::link(Node *node) { if (!node) return; makeRoot(); access(); node->access(); left = node; node->parent = this; update(); } void Node::cut() { if (!parent) return; access(); if (left){ left->parent = nullptr; left = nullptr; } splay(); } void Node::changeWeight(int weight_) { makeRoot(); weight[0] = weight_; update(); } Node* Node::findCenter() { makeRoot(); int full = size[0]; if (full == 0) return this; int half = full / 2; Node *n = this; while (true){ n->propagate(); if (n->left){ if (full - n->size[0] + n->left->size[0] > half){ n = n->left; continue; } } if (n->right){ if (n->right->size[0] > half){ n = n->right; continue; } } if (!n->hNode.empty()){ auto I = n->hNode.end(); --I; if (I->first > half){ n = I->second; continue; } } break; } n->makeRoot(); return n; } int main() { int N,Q; scanf ("%d %d",&N,&Q); LinkCutTree lct(N); map, Node *> edge; int enc = 0; while (Q--){ int o; scanf ("%d",&o); if (o == 1){ int x,y,c; scanf ("%d %d %d",&x,&y,&c); x = (x - 1 + enc) % N; y = (y - 1 + enc) % N; if (x > y) swap(x,y); Node *e = new Node(0,c); lct.getNode(x)->link(e); lct.getNode(y)->link(e); edge[{x,y}] = e; } else if (o == 2){ int x,y; scanf ("%d %d",&x,&y); x = (x - 1 + enc) % N; y = (y - 1 + enc) % N; if (x > y) swap(x,y); auto I = edge.find({x,y}); delete I->second; edge.erase(I); } else if (o == 3){ int x; scanf ("%d",&x); x = (x - 1 + enc) % N; auto v = lct.getNode(x); v->changeWeight(1 - v->weight[0]); auto c = v->findCenter(); long long res = c->sum[c->reverse]; enc = (enc + res) % N; printf ("%lld\n",res); } } return 0; }