隐藏
「LibreOJ121」「离线可过」动态图连通性 - 线段树分治 | Bill Yang's Blog

路终会有尽头,但视野总能看到更远的地方。

0%

「LibreOJ121」「离线可过」动态图连通性 - 线段树分治

题目大意

    你要维护一张无向简单图。你被要求加入删除一条边及查询两个点是否连通。
    $0$:加入一条边。保证它不存在。
    $1$:删除一条边。保证它存在。
    $2$:查询两个点是否联通。


题目分析

线段树分治模板题?
线段树分治和cdq分治真的很像。
强制在线只能用ETT做了。
对时间建立线段树,故每条边在线段树中对应连续的区间,将边拆分到连续区间的线段树结点中存下来。
接下来我们按照Dfs序遍历这一棵线段树,每进入一个区间就将其区间包含的边用并查集连接起来,每退出一个区间就在并查集中删除这条边的影响。如何撤销并查集?可以使用这里介绍过的带撤销并查集进行维护。
递归到达叶子结点时即可回答询问。


代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
#include<algorithm>
#include<iostream>
#include<iomanip>
#include<cstring>
#include<cstdlib>
#include<vector>
#include<cstdio>
#include<cmath>
#include<queue>
using namespace std;

inline const int Get_Int() {
int num=0,bj=1;
char x=getchar();
while(x<'0'||x>'9') {
if(x=='-')bj=-1;
x=getchar();
}
while(x>='0'&&x<='9') {
num=num*10+x-'0';
x=getchar();
}
return num*bj;
}

const int maxn=5005,maxm=500005;

int n,m,map[maxn][maxn],top=0,father[maxn];

struct St {
int x,y,fx,fy;
} S[maxm];

struct Question {
int opt,x,y;
} Q[maxm];

struct Tree {
int left,right;
vector<int>vec;
Tree(int l=0,int r=0):left(l),right(r),vec(vector<int>()) {}
};

int Get_Father(int x) {
if(father[x]<0)return x;
else return Get_Father(father[x]);
}

void merge(int x,int y) {
int fx=Get_Father(x),fy=Get_Father(y);
if(fx==fy)return;
S[++top]=(St) {fx,fy,father[fx],father[fy]};
if(father[fx]>father[fy])swap(fx,fy);
father[fx]+=father[fy];
father[fy]=fx;
}

struct Segment_Tree {
Tree tree[maxm*4];
#define ls index<<1
#define rs index<<1|1
void build(int index,int Left,int Right) {
tree[index]=Tree(Left,Right);
if(Left==Right)return;
int mid=(Left+Right)>>1;
build(ls,Left,mid);
build(rs,mid+1,Right);
}
void insert(int index,int Left,int Right,int v) {
if(Right<tree[index].left||Left>tree[index].right)return;
if(Left<=tree[index].left&&Right>=tree[index].right) {
tree[index].vec.push_back(v);
return;
}
insert(ls,Left,Right,v);
insert(rs,Left,Right,v);
}
void binary(int index) {
int tmptop=top;
for(int tmp:tree[index].vec)merge(Q[tmp].x,Q[tmp].y);
if(tree[index].left==tree[index].right) {
if(Q[tree[index].left].opt==2)putchar(Get_Father(Q[tree[index].left].x)==Get_Father(Q[tree[index].left].y)?'Y':'N'),putchar('\n');
} else binary(ls),binary(rs);
while(top>tmptop) {
father[S[top].x]=S[top].fx;
father[S[top].y]=S[top].fy;
top--;
}
}
} st;

int main() {
n=Get_Int();
m=Get_Int();
st.build(1,1,m);
for(int i=1; i<=m; i++) {
Q[i].opt=Get_Int();
Q[i].x=Get_Int();
Q[i].y=Get_Int();
if(Q[i].x>Q[i].y)swap(Q[i].x,Q[i].y);
if(Q[i].opt==0)map[Q[i].x][Q[i].y]=i;
else if(Q[i].opt==1)st.insert(1,map[Q[i].x][Q[i].y],i,i),map[Q[i].x][Q[i].y]=0;
}
for(int i=1; i<=n; i++)
for(int j=i+1; j<=n; j++)
if(map[i][j])st.insert(1,map[i][j],m,map[i][j]);
for(int i=1; i<=n; i++)father[i]=-1;
st.binary(1);
return 0;
}
姥爷们赏瓶冰阔落吧~