「CF1217F」Forced Online Queries Problem【线段树分治 或 ETT】

F. Forced Online Queries Problem

time limit per test 5 seconds
memory limit per test 256 megabytes
input standard input
output standard output

You are given an undirected graph with nn vertices numbered from 11 to nn. Initially there are no edges.

You are asked to perform some queries on the graph. Let lastlast be the answer to the latest query of the second type, it is set to 00 before the first such query. Then the queries are the following:

1 x y(1x,yn,x!=y)1\ x\ y (1\leq x,y\leq n, x!=y) — add an undirected edge between the vertices (x+last1)mod n+1(x+last−1) mod\ n+1 and (y+last1)mod n+1(y+last−1) mod\ n+1 if it doesn’t exist yet, otherwise remove it;
2 x y(1x,yn,x!=y)2\ x\ y (1\leq x,y\leq n, x!=y) — check if there exists a path between the vertices (x+last1)mod n+1(x+last−1) mod\ n+1 and (y+last1)mod n+1(y+last−1) mod\ n+1, which goes only through currently existing edges, and set lastlast to 11 if so and 00 otherwise.
Good luck!

Input

The first line contains two integer numbers nn and mm (2n,m2×105)(2\leq n,m\leq 2\times 10^5) — the number of vertices and the number of queries, respectively.

Each of the following mm lines contains a query of one of two aforementioned types. It is guaranteed that there is at least one query of the second type.

Output

Print a string, consisting of characters 0'0' and 1'1'. The ithi-th character should be the answer to the ithi-th query of the second type. Therefore the length of the string should be equal to the number of queries of the second type.

Examples

input
5 9
1 1 2
1 1 3
2 3 2
1 2 4
2 3 4
1 2 4
2 3 4
1 1 3
2 4 3
output
1010
input
3 9
1 1 2
1 2 3
1 3 1
2 1 3
1 3 2
2 2 3
1 1 2
2 1 2
2 1 2
output
1101

Note

The converted queries in the first example are:


1 1 2
1 1 3
2 3 2
1 3 5
2 4 5
1 2 4
2 3 4
1 2 4
2 5 4

The converted queries in the second example are:


1 1 2
1 2 3
1 3 1
2 1 3
1 1 3
2 3 1
1 2 3
2 2 3
2 1 2

题意

  • 就是让你维护动态动态图的连通性,然后“强制在线”

题解

  • 首先离线做法的话就是一个线段树分治的裸题
  • 实际上是一个假的强制在线,因为lastanslastans只可能是0或者1,所以可以处理最多2×m2\times m种询问,放到线段树上,然后在分治的过程中用一个mapmap记录一下每一条边是否有效,加到并查集的边的时候判断一下是否有效
  • 当然也可以在线做,做法就是ETTETT,实际上这题是个原题,LOJ122,比赛的时候前几个大佬交的代码都是同一份ETTETT板子

离线代码


#include<bits/stdc++.h>

using namespace std;
const int maxn=2e5+10;
const int maxm=4e5+10;

int n,m,ans[maxn],lastans=0;
map<int,int> exist[maxn];
struct operate{
    int opt,x,y;
    operate(int o=0,int a=0,int b=0) {
        opt=o;x=a;y=b;
    }
}o[maxm],sta[maxm];

namespace dsu{
    int fa[maxn],dep[maxn],tot;  //tot表示栈sta里的元素个数
    void init(int k) {
        tot=0;
        for(int i=1;i<=k;i++) fa[i]=i,dep[i]=0;
    }
    int find(int x) {
        return fa[x]==x?x:find(fa[x]);
    }
    void merge(int x,int y) {
        x=find(x),y=find(y);
        if(x==y) return;
        if(dep[x]>dep[y]) swap(x,y);
        if(dep[x]==dep[y]) dep[y]++;
        sta[++tot]=operate(0,x,y);  //注意栈中元素的构造函数
        fa[x]=y;
    }

    void undo(int id) {
        while(tot>id) {
            int x=sta[tot].x,y=sta[tot--].y;
            if(dep[y]==dep[x]+1) dep[y]--;
            fa[x]=x;
        }
    }
};
using namespace dsu;

namespace segment_tree{
    vector<operate> add[maxm<<2];
    void update(int id,int L,int R,int l,int r,operate k) {
        if(L>=l&&R<=r) {add[id].push_back(k);return;}
        int mid=(L+R)>>1;
        if(l<=mid) update(id<<1,L,mid,l,r,k);
        if(r>mid) update(id<<1|1,mid+1,R,l,r,k);
    }
    void work(int id,int L,int R) {
        int now=tot;
        for(int i=0;i<add[id].size();i++) {
            if(exist[add[id][i].x][add[id][i].y]) {
                merge(add[id][i].x,add[id][i].y);
            }
        }
        if(L==R) {
            if(o[L].opt==2) lastans=ans[L]=(find(o[L].x)==find(o[L].y));
            o[L+1].x=(o[L+1].x+lastans-1)%n+1,o[L+1].y=(o[L+1].y+lastans-1)%n+1;
            if(o[L+1].x>o[L+1].y) swap(o[L+1].x,o[L+1].y);
            if(o[L+1].opt==1) exist[o[L+1].x][o[L+1].y]^=1;
        }
        else {
            int mid=(L+R)>>1;
            work(id<<1,L,mid);work(id<<1|1,mid+1,R);
        }
        undo(now); //叶子结点也要undo
    }
};
using namespace segment_tree;


int main()
{
    scanf("%d %d",&n,&m);
    init(n);
    for(int i=1;i<=m;i++) {
        scanf("%d %d %d",&o[i].opt,&o[i].x,&o[i].y);
        if(o[i].x>o[i].y) swap(o[i].x,o[i].y);
        if(o[i].opt==1) {
            int x=o[i].x,y=o[i].y;
            if(exist[x].count(y)) update(1,1,m,exist[x][y],i,o[i]);
            exist[x][y]=i;

            x=x%n+1,y=y%n+1;
            if(x>y) swap(x,y);
            if(exist[x].count(y)) update(1,1,m,exist[x][y],i,operate(1,x,y));
            exist[x][y]=i;
        }
    }
    for(int i=1;i<=n;i++) for(map<int,int>::iterator it=exist[i].begin();it!=exist[i].end();it++) if(it->second!=m) update(1,1,m,it->second,m,operate(1,i,it->first));
    for(int i=1;i<=n;i++) exist[i].clear();
    if(o[1].opt==1) exist[o[1].x][o[1].y]=1;
    work(1,1,m);
    for(int i=1;i<=m;i++) if(o[i].opt==2) printf(ans[i]?"1":"0");
    return 0; 
}

在线做法(ETTETT)

#include "bits/stdc++.h"
using namespace std;

struct Xor128 {
    unsigned x, y, z, w;
    Xor128() : x(123456789), y(362436069), z(521288629), w(88675123) {}
    unsigned next() {
        unsigned t = x ^ (x << 11);
        x = y;
        y = z;
        z = w;
        return w = w ^ (w >> 19) ^ (t ^ (t >> 8));
    }
    inline unsigned next(unsigned n) { return next() % n; }
};

template <typename Node>
struct BottomupTreap {
    Xor128 rng;
    typedef Node *Ref;
    static int size(Ref t) { return !t ? 0 : t->size; }
    unsigned nextRand() { return rng.next(); }
private:
    bool choiceRandomly(Ref l, Ref r) { return l->priority < r->priority; }
public:
    Ref join(Ref l, Ref r) {
        if (!l) return r;
        if (!r) return l;
        Ref t = NULL;
        unsigned long long dirs = 0;
        int h;
        for(h = 0;; ++h) {
            if (h >= sizeof(dirs) * 8 - 2) { t = join(l->right, r->left);dirs = dirs << 2 | 1; h++; break;}
            dirs <<= 1;
            if (choiceRandomly(l, r)) {
                Ref c = l->right;
                if (!c) {t = r; r = r->parent; break; }
                l = c;
            } else {
                dirs |= 1;
                Ref c = r->left;
                if (!c) { t = l; l = l->parent; break; }
                r = c;
            }
        }
        for (; h >= 0; --h) {
            if (!(dirs & 1)) { Ref p = l->parent; t = l->linkr(t); l = p; } 
            else {Ref p = r->parent; t = r->linkl(t); r = p; }
            dirs >>= 1;
        }
        return t;
    }
    typedef pair<Ref, Ref> RefPair;
    RefPair split2(Ref t) {
        Ref p, l = t->left, r = t;
        Node::cut(l);
        t->linkl(NULL);
        while ((p = t->parent)) {
            t->parent = NULL;
            if (p->left == t) r = p->linkl(r);
            else l = p->linkr(l);
            t = p;
        }
        return RefPair(l, r);
    }
    RefPair split3(Ref t) {
        Ref p, l = t->left, r = t->right;
        Node::cut(l), Node::cut(r);
        t->linklr(NULL, NULL);
        while ((p = t->parent)) {
            t->parent = NULL;
            if (p->left == t) r = p->linkl(r);
            else l = p->linkr(l);
            t = p;
        }
        return RefPair(l, r);
    }
    Ref cons(Ref h, Ref t) {
        assert(size(h) == 1);
        if (!t) return h;
        Ref u = NULL;
        while (true) {
            if (choiceRandomly(h, t)) { Ref p = t->parent; u = h->linkr(t); t = p; break; }
            Ref l = t->left;
            if (!l) { u = h; break; }
            t = l;
        }
        while (t) {
            u = t->linkl(u);
            t = t->parent;
        }
        return u;
    }
};

class EulerTourTreeWithMarks {
    struct Node {
        typedef BottomupTreap<Node> BST;
        Node *left, *right, *parent;
        int size;
        unsigned priority;
        char marks, markUnions;
        Node() : left(NULL), right(NULL), parent(NULL), size(1), priority(0), marks(0), markUnions(0) {}
        inline Node *update() {
            int size_t = 1, markUnions_t = marks;
            if (left) {
                size_t += left->size;
                markUnions_t |= left->markUnions;
            }
            if (right) {
                size_t += right->size;
                markUnions_t |= right->markUnions;
            }
            size = size_t, markUnions = markUnions_t;
            return this;
        }
        inline Node *linkl(Node *c) {
            if ((left = c)) c->parent = this;
            return update();
        }
        inline Node *linkr(Node *c) {
            if ((right = c)) c->parent = this;
            return update();
        }
        inline Node *linklr(Node *l, Node *r) {
            if ((left = l)) l->parent = this;
            if ((right = r)) r->parent = this;
            return update();
        }
        static Node *cut(Node *t) {
            if (t) t->parent = NULL;
            return t;
        }

        static const Node *findRoot(const Node *t) {
            while (t->parent) t = t->parent;
            return t;
        }
        static pair<Node *, int> getPosition(Node *t) {
            int k = BST::size(t->left);
            Node *p;
            while ((p = t->parent)) {
                if (p->right == t) k += BST::size(p->left) + 1;
                t = p;
            }
            return make_pair(t, k);
        }
        static const Node *findHead(const Node *t) {
            while (t->left) t = t->left;
            return t;
        }
        static void updatePath(Node *t) {
            while (t) {
                t->update();
                t = t->parent;
            }
        }
    };
    typedef Node::BST BST;
    BST bst;
    vector<Node> nodes;
    vector<int> firstArc;
    vector<bool> edgeMark, vertexMark;
    inline int getArcIndex(const Node *a) const { return a - &nodes[0]; }
    inline int arc1(int ei) const { return ei; }
    inline int arc2(int ei) const { return ei + (numVertices() - 1); }
public:
    inline int numVertices() const { return firstArc.size(); }
    inline int numEdges() const { return numVertices() - 1; }
    inline bool getEdgeMark(int a) const { return a < numEdges() ? edgeMark[a] : false; }
    inline bool getVertexMark(int v) const { return vertexMark[v]; }

private:
    void updateMarks(int a, int v) {
        Node *t = &nodes[a];
        t->marks = getEdgeMark(a) << 0 | getVertexMark(v) << 1;
        Node::updatePath(t);
    }
    void firstArcChanged(int v, int a, int b) {
        if (a != -1) updateMarks(a, v);
        if (b != -1) updateMarks(b, v);
    }

public:
    class TreeRef {
        friend class EulerTourTreeWithMarks;
        const Node *ref;

    public:
        TreeRef() {}
        TreeRef(const Node *ref_) : ref(ref_) {}
        bool operator==(const TreeRef &that) const { return ref == that.ref; }
        bool operator!=(const TreeRef &that) const { return ref != that.ref; }
        bool isIsolatedVertex() const { return ref == NULL; }
    };

    void init(int N) {
        int M = N - 1;
        firstArc.assign(N, -1);
        nodes.assign(M * 2, Node());
        for (int i = 0; i < M * 2; i++) nodes[i].priority = bst.nextRand();
        edgeMark.assign(M, false);
        vertexMark.assign(N, false);
    }

    TreeRef getTreeRef(int v) const {
        int a = firstArc[v];
        return TreeRef(a == -1 ? NULL : Node::findRoot(&nodes[a]));
    }

    bool isConnected(int v, int w) const {
        if (v == w) return true;
        int a = firstArc[v], b = firstArc[w];
        if (a == -1 || b == -1) return false;
        return Node::findRoot(&nodes[a]) == Node::findRoot(&nodes[b]);
    }

    static int getSize(TreeRef t) {
        if (t.isIsolatedVertex()) return 1;
        else return t.ref->size / 2 + 1;
    }

    void link(int ti, int v, int w) {
        int a1 = arc1(ti), a2 = arc2(ti);
        if (v > w) swap(a1, a2);
        int va = firstArc[v], wa = firstArc[w];
        Node *l, *m, *r;
        if (va != -1) {
            pair<Node *, Node *> p = bst.split2(&nodes[va]);
            m = bst.join(p.second, p.first);
        } else {
            m = NULL;
            firstArc[v] = a1;
            firstArcChanged(v, -1, a1);
        }
        if (wa != -1) {
            pair<Node *, Node *> p = bst.split2(&nodes[wa]);
            l = p.first, r = p.second;
        } else {
            l = r = NULL;
            firstArc[w] = a2;
            firstArcChanged(w, -1, a2);
        }
        m = bst.cons(&nodes[a2], m);
        r = bst.cons(&nodes[a1], r);
        bst.join(bst.join(l, m), r);
    }

    void cut(int ti, int v, int w) {
        if (v > w)swap(v, w);
        int a1 = arc1(ti), a2 = arc2(ti);
        pair<Node *, Node *> p = bst.split3(&nodes[a1]);
        int prsize = BST::size(p.second);
        pair<Node *, Node *> q = bst.split3(&nodes[a2]);
        Node *l, *m, *r;
        if (p.second == &nodes[a2] || BST::size(p.second) != prsize) {
            l = p.first, m = q.first, r = q.second;
        }else {
            swap(v, w);swap(a1, a2);
            l = q.first, m = q.second, r = p.second;
        }
        if (firstArc[v] == a1) {
            int b;
            if (r != NULL) b = getArcIndex(Node::findHead(r));
            else b = !l ? -1 : getArcIndex(Node::findHead(l));
            firstArc[v] = b;
            firstArcChanged(v, a1, b);
        }
        if (firstArc[w] == a2) {
            int b = !m ? -1 : getArcIndex(Node::findHead(m));
            firstArc[w] = b;
            firstArcChanged(w, a2, b);
        }

        bst.join(l, r);
    }

    void changeEdgeMark(int ti, bool b) {
        assert(ti < numEdges());
        edgeMark[ti] = b;
        Node *t = &nodes[ti];
        t->marks = (b << 0) | (t->marks & (1 << 1));
        Node::updatePath(t);
    }
    void changeVertexMark(int v, bool b) {
        vertexMark[v] = b;
        int a = firstArc[v];
        if (a != -1) {
            Node *t = &nodes[a];
            t->marks = (t->marks & (1 << 0)) | (b << 1);
            Node::updatePath(t);
        }
    }

    template <typename Callback>
    bool enumMarkedEdges(TreeRef tree, Callback callback) const {
        return enumMarks<0, Callback>(tree, callback);
    }
    template <typename Callback>
    bool enumMarkedVertices(TreeRef tree, Callback callback) const {
        return enumMarks<1, Callback>(tree, callback);
    }

private:
    template <int Mark, typename Callback>
    bool enumMarks(TreeRef tree, Callback callback) const {
        if (tree.isIsolatedVertex())
            return true;
        const Node *t = tree.ref;
        if (t->markUnions >> Mark & 1)
            return enumMarksRec<Mark, Callback>(t, callback);
        else
            return true;
    }
    template <int Mark, typename Callback>
    bool enumMarksRec(const Node *t, Callback callback) const {
        const Node *l = t->left, *r = t->right;
        if (l && (l->markUnions >> Mark & 1)) if (!enumMarksRec<Mark, Callback>(l, callback)) return false;
        if (t->marks >> Mark & 1) if (!callback(getArcIndex(t))) return false;
        if (r && (r->markUnions >> Mark & 1)) if (!enumMarksRec<Mark, Callback>(r, callback)) return false;
        return true;
    }

public:
    void debugEnumEdges(vector<int> &out_v) const {
        int M = numEdges();
        for (int ti = 0; ti < M; ti++) {
            const Node *t = &nodes[ti];
            if (t->left || t->right || t->parent)
                out_v.push_back(ti);
        }
    }
};

class HolmDeLichtenbergThorup {
    typedef HolmDeLichtenbergThorup This;
    typedef EulerTourTreeWithMarks Forest;
    typedef Forest::TreeRef TreeRef;
    int numVertices_m;
    int numSamplings;
    vector<Forest> forests;
    vector<char> edgeLevel;
    vector<int> treeEdgeIndex;         
    vector<int> treeEdgeMap;          
    vector<int> treeEdgeIndexFreeList;  
    vector<int> arcHead;
    vector<vector<int>> firstIncidentArc;
    vector<int> nextIncidentArc, prevIncidentArc;
    vector<bool> edgeVisited;
    vector<int> visitedEdges; 
    int arc1(int ei) const { return ei; }
    int arc2(int ei) const { return numMaxEdges() + ei; }
    int arcEdge(int i) const { return i >= numMaxEdges() ? i - numMaxEdges() : i; }
    bool replace(int lv, int v, int w) {
        Forest &forest = forests[lv];
        TreeRef vRoot = forest.getTreeRef(v), wRoot = forest.getTreeRef(w);
        assert(vRoot.isIsolatedVertex() || wRoot.isIsolatedVertex() || vRoot != wRoot);
        int vSize = forest.getSize(vRoot), wSize = forest.getSize(wRoot);
        int u,uSize;
        TreeRef uRoot;
        if (vSize <= wSize) u = v, uRoot = vRoot, uSize = vSize;
        else u = w, uRoot = wRoot, uSize = wSize;
        int replacementEdge = -1;
        enumIncidentArcs(forest, uRoot, u, lv, FindReplacementEdge(uRoot, &replacementEdge));
        if (replacementEdge != -1 && (int)visitedEdges.size() + 1 <= numSamplings) {
            deleteNontreeEdge(replacementEdge);
            addTreeEdge(replacementEdge);
            for (int i = 0; i < (int)visitedEdges.size(); i++) edgeVisited[visitedEdges[i]] = false;
            visitedEdges.clear();
            return true;
        }
        for (int i = 0; i < (int)visitedEdges.size(); i++) {
            int ei = visitedEdges[i];
            edgeVisited[ei] = false;
            deleteNontreeEdge(ei);
            ++edgeLevel[ei];
            insertNontreeEdge(ei);
        }
        visitedEdges.clear();
        forest.enumMarkedEdges(uRoot, EnumLevelTreeEdges(this));
        for (int i = 0; i < (int)visitedEdges.size(); i++) {
            int ti = visitedEdges[i];
            int ei = treeEdgeMap[ti];
            int v = arcHead[arc2(ei)], w = arcHead[arc1(ei)];
            int lv = edgeLevel[ei];
            edgeLevel[ei] = lv + 1;
            forests[lv].changeEdgeMark(ti, false);
            forests[lv + 1].changeEdgeMark(ti, true);
            forests[lv + 1].link(ti, v, w);
        }
        visitedEdges.clear();
        if (replacementEdge != -1) {
            deleteNontreeEdge(replacementEdge);
            addTreeEdge(replacementEdge);
            return true;
        }else if (lv > 0) return replace(lv - 1, v, w);
        else return false;
    }

    struct EnumLevelTreeEdges {
        This *thisp;
        EnumLevelTreeEdges(This *thisp_) : thisp(thisp_) {}

        inline bool operator()(int a) {
            thisp->enumLevelTreeEdges(a);
            return true;
        }
    };
    void enumLevelTreeEdges(int ti) { visitedEdges.push_back(ti); }

    template <typename Callback>
    bool enumIncidentArcs(Forest &forest, TreeRef t, int u, int lv, Callback callback) {
        if (t.isIsolatedVertex())
            return enumIncidentArcsWithVertex<Callback>(lv, u, callback);
        else
            return forest.enumMarkedVertices(t, EnumIncidentArcs<Callback>(this, lv, callback));
    }

    template <typename Callback>
    struct EnumIncidentArcs {
        This *thisp;
        int lv;
        Callback callback;
        EnumIncidentArcs(This *thisp_, int lv_, Callback callback_)
            : thisp(thisp_), lv(lv_), callback(callback_) {}
        inline bool operator()(int tii) const {
            return thisp->enumIncidentArcsWithTreeArc(tii, lv, callback);
        }
    };

    template <typename Callback>
    bool enumIncidentArcsWithTreeArc(int tii, int lv, Callback callback) {
        bool dir = tii >= numVertices() - 1;
        int ti = dir ? tii - (numVertices() - 1) : tii;
        int ei = treeEdgeMap[ti];
        int v = arcHead[arc2(ei)], w = arcHead[arc1(ei)];
        int u = !(dir != (v > w)) ? v : w;
        return enumIncidentArcsWithVertex(lv, u, callback);
    }
    template <typename Callback>
    bool enumIncidentArcsWithVertex(int lv, int u, Callback callback) {
        int it = firstIncidentArc[lv][u];
        while (it != -1) {
            if (!callback(this, it))
                return false;
            it = nextIncidentArc[it];
        }
        return true;
    }

    struct FindReplacementEdge {
        TreeRef uRoot;
        int *replacementEdge;
        FindReplacementEdge(TreeRef uRoot_, int *replacementEdge_)
            : uRoot(uRoot_), replacementEdge(replacementEdge_) {}
        inline bool operator()(This *thisp, int a) const {
            return thisp->findReplacementEdge(a, uRoot, replacementEdge);
        }
    };
    bool findReplacementEdge(int a, TreeRef uRoot, int *replacementEdge) {
        int ei = arcEdge(a);
        if (edgeVisited[ei]) return true;
        int lv = edgeLevel[ei];
        TreeRef hRoot = forests[lv].getTreeRef(arcHead[a]);
        if (hRoot.isIsolatedVertex() || hRoot != uRoot) {
            *replacementEdge = ei;
            return false;
        }
        edgeVisited[ei] = true;
        visitedEdges.push_back(ei);
        return true;
    }

    void addTreeEdge(int ei) {
        int v = arcHead[arc2(ei)], w = arcHead[arc1(ei)];
        int lv = edgeLevel[ei];
        int ti = treeEdgeIndexFreeList.back();
        treeEdgeIndexFreeList.pop_back();
        treeEdgeIndex[ei] = ti;
        treeEdgeMap[ti] = ei;
        forests[lv].changeEdgeMark(ti, true);
        for (int i = 0; i <= lv; i++) forests[i].link(ti, v, w);
    }

    void insertIncidentArc(int a, int v) {
        int ei = arcEdge(a);
        int lv = edgeLevel[ei];
        assert(treeEdgeIndex[ei] == -1);
        int next = firstIncidentArc[lv][v];
        firstIncidentArc[lv][v] = a;
        nextIncidentArc[a] = next;
        prevIncidentArc[a] = -1;
        if (next != -1) prevIncidentArc[next] = a;
        if (next == -1) forests[lv].changeVertexMark(v, true);
    }

    void deleteIncidentArc(int a, int v) {
        int ei = arcEdge(a);
        int lv = edgeLevel[ei];
        assert(treeEdgeIndex[ei] == -1);
        int next = nextIncidentArc[a], prev = prevIncidentArc[a];
        nextIncidentArc[a] = prevIncidentArc[a] = -2;
        if (next != -1) prevIncidentArc[next] = prev;
        if (prev != -1) nextIncidentArc[prev] = next;
        else firstIncidentArc[lv][v] = next;
        if (next == -1 && prev == -1) forests[lv].changeVertexMark(v, false);
    }
    void insertNontreeEdge(int ei) {
        int a1 = arc1(ei), a2 = arc2(ei);
        insertIncidentArc(a1, arcHead[a2]);
        insertIncidentArc(a2, arcHead[a1]);
    }
    void deleteNontreeEdge(int ei) {
        int a1 = arc1(ei), a2 = arc2(ei);
        deleteIncidentArc(a1, arcHead[a2]);
        deleteIncidentArc(a2, arcHead[a1]);
    }
public:
    HolmDeLichtenbergThorup() : numVertices_m(0), numSamplings(0) {}
    int numVertices() const { return numVertices_m; }
    int numMaxEdges() const { return edgeLevel.size(); }
    void init(int N, int M) {
        numVertices_m = N;
        int levels = 1;
        while (1 << levels <= N / 2) levels++;
        numSamplings = (int)(levels * 1);
        forests.resize(levels);
        for (int lv = 0; lv < levels; lv++) forests[lv].init(N);
        edgeLevel.assign(M, -1);
        treeEdgeIndex.assign(M, -1);
        treeEdgeMap.assign(N - 1, -1);
        treeEdgeIndexFreeList.resize(N - 1);
        for (int ti = 0; ti < N - 1; ti++) treeEdgeIndexFreeList[ti] = ti;
        arcHead.assign(M * 2, -1);
        firstIncidentArc.resize(levels);
        for (int lv = 0; lv < levels; lv++) firstIncidentArc[lv].assign(N, -1);
        nextIncidentArc.assign(M * 2, -2);
        prevIncidentArc.assign(M * 2, -2);
        edgeVisited.assign(M, false);
    }

    bool insertEdge(int ei, int v, int w) {
        if (!(0 <= ei && ei < numMaxEdges() && 0 <= v && v < numVertices() && 0 <= w && w < numVertices())) {
            system("pause");
        }
        assert(0 <= ei && ei < numMaxEdges() && 0 <= v && v < numVertices() && 0 <= w && w < numVertices());
        assert(edgeLevel[ei] == -1);
        int a1 = arc1(ei), a2 = arc2(ei);
        arcHead[a1] = w, arcHead[a2] = v;
        bool treeEdge = !forests[0].isConnected(v, w);
        edgeLevel[ei] = 0;
        if (treeEdge) addTreeEdge(ei);
        else {
            treeEdgeIndex[ei] = -1;
            if (v != w) insertNontreeEdge(ei);
        }
        return treeEdge;
    }

    bool deleteEdge(int ei) {
        assert(0 <= ei && ei < numMaxEdges() && edgeLevel[ei] != -1);
        int a1 = arc1(ei), a2 = arc2(ei);
        int v = arcHead[a2], w = arcHead[a1];
        int lv = edgeLevel[ei];
        int ti = treeEdgeIndex[ei];
        bool splitted = false;
        if (ti != -1) {
            treeEdgeMap[ti] = -1;
            treeEdgeIndex[ei] = -1;
            treeEdgeIndexFreeList.push_back(ti);
            for (int i = 0; i <= lv; i++) forests[i].cut(ti, v, w);
            forests[lv].changeEdgeMark(ti, false);
            splitted = !replace(lv, v, w);
        }else if(v != w) deleteNontreeEdge(ei);
        arcHead[a1] = arcHead[a2] = -1;
        edgeLevel[ei] = -1;
        return splitted;
    }

    bool isConnected(int v, int w) const { return forests[0].isConnected(v, w); }
};
vector<int> te;
map<int, map<int, int>> ee;
map<pair<int,int>,int> memor;
int lastans = 0,n,m,opt,u,v;
int main() {
    scanf("%d %d",&n,&m);
    for (int i = m; i > 0; --i) te.push_back(i);
    typedef HolmDeLichtenbergThorup FullyDynamicConnectivity;
    FullyDynamicConnectivity fdc;
    fdc.init(n + 1, m + 1);
    while(m--){
        scanf("%d %d %d",&opt,&u,&v);
        u=(u+lastans-1)%n+1;
        v=(v+lastans-1)%n+1;
        if(u>v) swap(u,v);
        if(opt==1) {
            if(memor.count(make_pair(u,v))) {
                fdc.deleteEdge(ee[u][v]);
                ee[u].erase(v);
                memor.erase(make_pair(u,v));
            }else {
                ee[u][v] = te.back();
                te.pop_back();
                fdc.insertEdge(ee[u][v], u, v);
                memor[make_pair(u,v)]=1;
            }
        }else {
            lastans=fdc.isConnected(u,v);
            printf("%c",'0'+lastans);
        }
    }
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章