题目大意
给出 n 个点,
数据范围
1≤n≤105,1≤m≤2×105,1≤c≤4
思路
我们将整个操作序列视为时间轴,考虑线段树分治,用链表预处理出每条边在图中出现的时间,然后线段树上分治,分治的时候,用按秩合并的并查集维护连通性,我们分治到叶子节点的时候,必然是当前询问的那些边没有建出来,由于图是连通的,所以直接询问删除的边是否连通即可。
考虑这样做的时候,我们分出来的区间的个数,每一个询问操作会增加四个线段树上的标记,所以总的区间数是 O(n) 级别的,还有并查集,所以总复杂度为 O(qlognlogq)
代码常数比较大,卡着时限过的
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#include <map>
using std :: vector;
using std :: map;
template <typename Tp>Tp Max(const Tp &a, const Tp &b) {return a > b ? a : b;}
template <typename Tp>Tp Min(const Tp &a, const Tp &b) {return a < b ? a : b;}
template <typename Tp>void Read(Tp &x) {
Tp in = 0, f = 1; char ch = getchar();
while(ch<'0' || ch>'9') {if(ch=='-') f = -1; ch = getchar();}
while(ch>='0' && ch<='9') {in = in*10+ch-'0'; ch = getchar();}
x = in*f;
}
const int SN = 100000 + 10;
const int SM = 200000 + 10;
int rnk[SN], fa[SN], sta[SM * 50], n, m, top, QUE;
struct Edge {
int u, v, l, r;
};
struct EDGE {
int u, v;
}Q[SM];
struct Que {
int k;
int c[5];
}q[SN];
vector <Edge> all;
vector <int> time[SM];
int find(int x) {
while(fa[x] != x) x = fa[x];
return fa[x];
}
void Unionn(int x, int y) {
if(rnk[x] > rnk[y]) std :: swap(x, y);
if(rnk[x] == rnk[y]) rnk[y]++, sta[++top] = -y;
fa[x] = y, sta[++top] = x;
}
void reverse(int bottom) {
int now;
while(top > bottom) {
now = sta[top--];
if(now < 0) rnk[-now]--;
else fa[now] = now;
}
}
void CDQ(int l, int r, vector <Edge> &p) {
int bottom = top;
vector <Edge> L, R;
vector <Edge> :: iterator it;
int mid = (l + r) >> 1;
int L1, R1, x, y, a, b;
for(it = p.begin(); it != p.end(); it++) {
x = (*it).u, y = (*it).v;
L1 = (*it).l, R1 = (*it).r;
a = find(x), b = find(y);
if(L1 == l && R1 == r) {
if(a != b) Unionn(a, b);
}
else {
if(L1 <= mid) {
Edge New = (*it);
if(New.r <= mid) L.push_back(New);
else New.r = mid, L.push_back(New);
}
if(R1 > mid) {
Edge New = (*it);
if(New.l > mid) R.push_back(New);
else New.l = mid + 1, R.push_back(New);
}
}
}
if(l == r) {
for(int i = 1; i <= q[l].k; i++) {
a = q[l].c[i];
x = Q[a].u, y = Q[a].v;
a = find(x), b = find(y);
if(a != b) {
puts("Disconnected"); reverse(bottom); return ;
}
}
puts("Connected"); reverse(bottom); return ;
}
CDQ(l, mid, L), CDQ(mid + 1, r, R);
reverse(bottom);
}
int main() {
int x, y, a, b;
Read(n), Read(m);
for(int i = 1; i <= n; i++) fa[i] = i;
for(int i = 1; i <= m; i++) {
Read(Q[i].u), Read(Q[i].v);
if(Q[i].u > Q[i].v) std :: swap(Q[i].u, Q[i].v);
}
Read(QUE);
for(int i = 1; i <= QUE; i++) {
Read(q[i].k);
for(int j = 1; j <= q[i].k; j++) {
Read(q[i].c[j]);
x = q[i].c[j];
time[x].push_back(i);
}
}
vector <int> :: iterator it;
for(int i = 1; i <= m; i++)
if(!time[i].size()) {
x = Q[i].u, y = Q[i].v;
a = find(x), b = find(y);
if(a != b) Unionn(a, b);
}
else {
int pre = 1;
for(it = time[i].begin(); it != time[i].end(); it++) {
if((*it) == pre) {pre = (*it) + 1; continue ;}
all.push_back((Edge){Q[i].u, Q[i].v, pre, (*it) - 1});
pre = (*it) + 1;
}
it--;
if((*it) != QUE) all.push_back((Edge){Q[i].u, Q[i].v, pre, QUE});
}
CDQ(1, QUE, all);
return 0;
}