Lojා121. Connectivity of "off line transitive" dynamic graphs (segment tree divide and conquer)

Keywords: C++

meaning of the title

The meaning of the question is very clear..

Sol

It's obvious that you can go directly to LCT..

But this problem allows offline, so there is a very ingenious offline approach, like what is called line tree divide and conquer??

The position of each edge in this question can be regarded as an interval.

We use line tree maintenance. Each node of the line segment tree maintains a vector indicating the existence interval of the edge covering the current node

Because the total number of sides is $M $, the total element in the line segment tree is at most $logM * M $, and the space can be guaranteed

If you want to output the answer, you need to go through the last dfs

The current connection point can be maintained with the concurrent query set, and the undo operation needs to be supported.

The complexity is guaranteed by rank merging without path compression.

In this way, every time I break my father.

 

I see that the rank merging in the solution is by degrees. I tried to merge by node size and found that it ran almost fast..

 

/*
Line tree partition
For the interval of each maintenance operation
And check the set to maintain connectivity, record the degree when maintaining, and merge by rank
When canceling, cancel the small degree.    
*/
#include<cstdio>
#include<vector>
using namespace std;
const int MAXN = 2 * 1e6 + 10;
inline int read() {
    char c = getchar(); int x = 0, f = 1;
    while(c < '0' || c > '9') {if(c == '-') f = -1; c = getchar();}
    while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
    return x * f;
}
int N, M;
int tim[5001][5001];//edge(i, j)Time of joining
int fa[MAXN];
struct Node {
    int x, deg;
}S[MAXN];
struct Query {
    int opt, x, y;
}Q[MAXN]; 
#define ls k << 1
#define rs k << 1 | 1
struct SegTree {
    int l, r;
    vector<int> id; 
}T[MAXN];
void Build(int k, int ll, int rr) {
    T[k] = (SegTree) {ll, rr};
    if(ll == rr) return ;
    int mid = ll + rr >> 1;
    Build(ls, ll, mid); Build(rs, mid + 1, rr);
}
void IntervalAdd(int k, int ll, int rr, int val) {
    if(ll <= T[k].l && T[k].r <= rr) {T[k].id.push_back(val); return ;}
    int mid = T[k].l + T[k].r >> 1;
    if(ll <= mid)IntervalAdd(ls, ll, rr, val); 
    if(rr >  mid)IntervalAdd(rs, ll, rr, val);
}
int Top, inder[MAXN];
int find(int x) {
    if(fa[x] == x) return x;
    else return find(fa[x]);
}
void unionn(int x, int y) {
    x = find(x); y = find(y);
    if(x == y) return;
    if(inder[x] < inder[y]) swap(x, y);
    fa[y] = x;
    S[++Top] = (Node) {y, inder[y]};
    if(inder[x] == inder[y]) S[++Top] = (Node) {x, inder[x] = inder[x] + inder[y]};//tag
}
void Delet(int cur) {
    while(Top > cur) {
        Node pre = S[Top--];
        fa[pre.x] = pre.x;
        inder[pre.x] = pre.deg;
    }
}
void dfs(int k) {
    int cur = Top;
    for(int i = 0; i < T[k].id.size(); i++) unionn(Q[T[k].id[i]].x, Q[T[k].id[i]].y);
    if(T[k].l == T[k].r) {
        if(Q[T[k].l].opt == 2)
            putchar(find(Q[T[k].l].x) == find(Q[T[k].l].y) ? 'Y' : 'N'), putchar('\n');
    } else dfs(ls), dfs(rs);
    
    Delet(cur);
}
int main() {
    N = read(); M = read();
    for(int i = 1; i <= N; i++) fa[i] = i, inder[i] = 1;
    Build(1, 1, M);//Building line segment tree with time as subscript 
    for(int i = 1; i <= M; i++) {
        int opt = read(), x = read(), y = read();
        if(x > y) swap(x, y);
        if(opt == 0) tim[x][y] = i;
        if(opt == 1) IntervalAdd(1, tim[x][y], i, i), tim[x][y] = 0;
        Q[i] = (Query) {opt, x, y};
    }
    for(int i = 1; i <= N; i++)
        for(int j = i; j <= N; j++)
            if(tim[i][j])
                IntervalAdd(1, tim[i][j], M, tim[i][j]);
    dfs(1);
    return 0;
}

Posted by imamferianto on Sun, 26 Jan 2020 09:41:29 -0800