Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- // clang-format off
- #define _CRT_SECURE_NO_WARNINGS
- #include <iostream>
- #include <iomanip>
- #include <bitset>
- #include <vector>
- #include <algorithm>
- #include <random>
- #include <map>
- #include <string>
- #include <set>
- #include <deque>
- #include <string>
- #include <cassert>
- #pragma GCC optimize("Ofast")
- using namespace std;
- const int N = 2e5 + 7, MOD = 1e9 + 7, C = 1000, C2 = 10;
- const long long INF = 1e18;
- const long double EPS = 1e-9;
- mt19937 rnd;
- struct Node {
- Node* l, * r, * p;
- int sz;
- int x, y;
- bool IsCycle, push;
- Node(int val) {
- l = nullptr;
- r = nullptr;
- p = nullptr;
- IsCycle = 0;
- push = 0;
- sz = 1;
- x = val;
- y = rnd();
- }
- };
- void push(Node* v) {
- if (v == nullptr || v->push == 0) {
- return;
- }
- v->push = 0;
- swap(v->l, v->r);
- if (v->l != nullptr) {
- v->l->push ^= 1;
- }
- if (v->r != nullptr) {
- v->r->push ^= 1;
- }
- }
- void recalc(Node* v) {
- if (v == nullptr) {
- return;
- }
- v->sz = 1;
- if (v->l != nullptr) {
- v->l->p = v;
- v->sz += v->l->sz;
- }
- if (v->r != nullptr) {
- v->r->p = v;
- v->sz += v->r->sz;
- }
- }
- int sz(Node* v) {
- if (v == nullptr) {
- return 0;
- }
- return v->sz;
- }
- struct CartesianTree {
- Node* nodes[N];
- int len;
- pair<Node*, Node*> split(Node* v, int k) {
- if (v != nullptr) {
- v->IsCycle = 0;
- }
- if (v == nullptr) {
- return { nullptr, nullptr };
- }
- push(v);
- if (sz(v->l) >= k) {
- if(v->l != nullptr)
- v->l->p = nullptr;
- auto res = split(v->l, k);
- v->l = res.second;
- recalc(v);
- return { res.first, v };
- }
- else {
- if(v->r != nullptr)
- v->r->p = nullptr;
- auto res = split(v->r, k - sz(v->l) - 1);
- v->r = res.first;
- recalc(v);
- return { v, res.second };
- }
- }
- Node* merge(Node* l, Node* r) {
- if (l != nullptr) {
- l->IsCycle = 0;
- }
- if (r != nullptr) {
- r->IsCycle = 0;
- }
- push(l);
- push(r);
- if (l == nullptr) return r;
- if (r == nullptr) return l;
- if (l->y > r->y) {
- l->r = merge(l->r, r);
- recalc(l);
- return l;
- }
- else {
- r->l = merge(l, r->l);
- recalc(r);
- return r;
- }
- }
- void rev(Node* v) {
- v->push ^= 1;
- }
- void PushUp(Node* v) {
- vector<Node*> kek;
- kek.clear();
- while (v->p != nullptr) {
- kek.push_back(v);
- v = v->p;
- }
- kek.push_back(v);
- reverse(kek.begin(), kek.end());
- for (auto u : kek) {
- push(u);
- }
- }
- void build(int n) {
- for (int i = 1; i <= n; i++) {
- auto nn = new Node(i);
- nodes[i] = nn;
- }
- }
- int GetInd(Node* v) {
- PushUp(v);
- int lft = sz(v->l);
- while (v->p != nullptr) {
- if (v == v->p->r) {
- lft++;
- lft += sz(v->p->l);
- }
- v = v->p;
- }
- return lft;
- }
- int GetParent(Node* v) {
- PushUp(v);
- while (v->p != nullptr) {
- v = v->p;
- }
- return v->x;
- }
- /*void unite(int u, int v) {
- int p1 = GetParent(nodes[u]);
- int p2 = GetParent(nodes[v]);
- if (p1 == p2) {
- nodes[p1]->IsCycle = 1;
- }
- else {
- if (GetInd(nodes[u]) != 0) {
- merge(nodes[p1], nodes[p2]);
- }
- else {
- merge(nodes[p2], nodes[p1]);
- }
- }
- }*/
- void unite(int u, int v) {
- int p1 = GetParent(nodes[u]);
- int p2 = GetParent(nodes[v]);
- if (p1 == p2) {
- nodes[p1]->IsCycle = 1;
- }else{
- int i1 = GetInd(nodes[u]);
- int i2 = GetInd(nodes[v]);
- if (i1 == 0 && i2 == 0) {
- rev(nodes[p1]);
- merge(nodes[p1], nodes[p2]);
- return;
- }
- if (i1 == 0) {
- rev(nodes[p1]);
- merge(nodes[p1], nodes[p2]);
- return;
- }
- merge(nodes[p1], nodes[p2]);
- }
- }
- void break_edge(int u, int v) {
- int p = GetParent(nodes[u]);
- int ind1 = GetInd(nodes[u]);
- int ind2 = GetInd(nodes[v]);
- if (!nodes[p]->IsCycle) {
- split(nodes[p], max(ind1, ind2));
- }
- else {
- if (max(ind1, ind2) == nodes[p]->sz - 1 && min(ind1, ind2) == 0) {
- nodes[p]->IsCycle = 0;
- return;
- }
- auto res = split(nodes[p], max(ind1, ind2));
- merge(res.second, res.first);
- }
- }
- int distance(int u, int v) {
- int p1 = GetParent(nodes[u]);
- int p2 = GetParent(nodes[v]);
- if (p1 != p2) {
- return 0;
- }
- int i1 = GetInd(nodes[v]);
- int i2 = GetInd(nodes[u]);
- int dist = abs(i1 - i2);
- if (nodes[p1]->IsCycle) {
- return min(dist, nodes[p1]->sz - dist);
- }
- return dist;
- }
- };
- CartesianTree CT;
- int n, m, q;
- signed main() {
- #ifdef _DEBUG
- freopen("input.txt", "r", stdin);
- #else
- std::ios::sync_with_stdio(false);
- cin.tie(0);
- #endif
- cin >> n >> m >> q;
- CT.build(n);
- for (int i = 1; i <= m; i++) {
- int u, v;
- cin >> u >> v;
- CT.unite(u, v);
- }
- for (int i = 0; i < q; i++) {
- char t;
- int u, v;
- cin >> t >> u >> v;
- if (t == '+') {
- CT.unite(u, v);
- }
- if (t == '-') {
- CT.break_edge(u, v);
- }
- if (t == '?') {
- cout << CT.distance(u, v) - 1 << "\n";
- }
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement