动态图完全连通性基本原理见LCT解法:洛谷P5247 动态图完全连通性 LCT解法
这里要换根,所以要用欧拉序的ETT,教程:洛谷 P2147 [SDOI2008] 洞穴勘测 ETT解法
由于原图中的一个点在ETT中有多个对应的occurrence,因此需要选择一个occurrence作为代表,将所有树边和非树边都挂在这个代表上。在删除ETT中的点时,需要检查一下它是不是代表,如果是的话要重新为其对应的原图上的点选一个代表,并把所有树边和非树边都转移到新的代表上。
代码:
#include <iostream>
#include <unordered_map>
#include <unordered_set>
#include <stack>
#include <cassert>
using namespace std;
#define MAXN 5011
#define MAX_LEVEL 15
struct ETT {
int c[2 * MAXN][2], fa[2 * MAXN];
int ori[MAXN * 2];
// node[v][u] is the occurrence of v after u.
// Corresponds to the directed edge from u to v.
// If u is the parent of v, then it is the first occurrence of v.
// i.e., if u is the parent of v, then uv is the first occurrence of v,
// vu is the last occurrence of v.
<int, int> node[MAXN];
unordered_map<int> free_list;
stackint tot;
int subtree_size[MAXN * 2];
// Only the representative occurrence could be the tag.
int representative[MAXN];
struct Tag {
// Only stores edges of this level.
<int> edges;
unordered_setint tag;
} tag_tree[MAXN * 2], tag_non_tree[MAXN * 2];
void update_tag(Tag tags[], int x) {
if (!tags[x].edges.empty()) {
[x].tag = x;
tags} else if (tags[ls(x)].tag) {
[x].tag = tags[ls(x)].tag;
tags} else if (tags[rs(x)].tag) {
[x].tag = tags[rs(x)].tag;
tags} else {
[x].tag = 0;
tags}
}
void reassign_representative(int& rt, int x) {
int u = ori[x];
if (x != representative[u])
return;
int y = node[u].begin()->second;
assert(x != y);
(y);
splay[u] = y;
representative(tag_non_tree[x].edges, tag_non_tree[y].edges);
swap(tag_non_tree, y);
update_tag(tag_tree[x].edges, tag_tree[y].edges);
swap(tag_tree, y);
update_tag= y;
rt }
std::unordered_set<int> take_out_edges(Tag type[], int x) {
assert(x == representative[ori[x]]);
(x);
splayauto tmp = std::unordered_set<int>();
(tmp, type[x].edges);
swap(type, x);
update_tagreturn std::move(tmp);
}
void give_edges(Tag type[], int x, unordered_set<int> edges) {
assert(x == representative[ori[x]]);
(x);
splay(edges, type[x].edges);
swap(type, x);
update_tag}
void add_directed_edge(Tag type[], int u, int v) {
int x = representative[u];
if (type[x].edges.empty()) {
(x);
splay[x].edges.insert(v);
type(type, x);
update_tag} else {
[x].edges.insert(v);
type}
}
void delete_directed_edge(Tag type[], int u, int v) {
int x = representative[u];
if (type[x].edges.size() == 1) {
(x);
splay[x].edges.erase(v);
type(type, x);
update_tag} else {
[x].edges.erase(v);
type}
}
void new_tree_edge(int u, int v) {
(u, v);
link_new(tag_tree, u, v);
add_directed_edge(tag_tree, v, u);
add_directed_edge}
inline int& ls(int rt) {
return c[rt][0];
}
inline int& rs(int rt) {
return c[rt][1];
}
inline int side(int x) {
return x == rs(fa[x]);
}
void pushup(int x) {
(tag_tree, x);
update_tag(tag_non_tree, x);
update_tag[x] = subtree_size[ls(x)] + subtree_size[rs(x)] + 1;
subtree_size}
// pushup(x) later
void __rotate_up(int x) {
int y = fa[x], z = fa[y], side_x = side(x), w = c[x][side_x ^ 1];
[x] = z;
faif (z)
[z][side(y)] = x;
cif (w)
[w] = y;
fa[y][side_x] = w;
c[y] = x;
fa[x][side_x ^ 1] = y;
c(y);
pushup}
void splay(int x, int to = 0) {
while (fa[x] != to) {
int y = fa[x];
if (fa[y] != to)
(side(x) == side(y) ? y : x);
__rotate_up(x);
__rotate_up}
(x);
pushup}
int new_node() {
int x;
if (!free_list.empty()) {
= free_list.top();
x .pop();
free_list} else {
= ++tot;
x }
return x;
}
void del_node(int x) {
.push(x);
free_list}
int __find_min_or_max(int rt, bool mx) {
while (c[rt][mx])
= c[rt][mx];
rt return rt;
}
int find_min_or_max(int rt, bool mx) {
= __find_min_or_max(rt, mx);
rt (rt);
splayreturn rt;
}
void __concat(int rt_x, int rt_y) {
[ori[rt_y]][ori[rt_x]] = rt_y;
node(rt_x) = rt_y;
rs[rt_y] = rt_x;
fa(rt_x);
pushup}
void concat(int& rt_x, int& rt_y) {
= find_min_or_max(rt_x, true);
rt_x = find_min_or_max(rt_y, false);
rt_y (rt_x, rt_y);
__concat}
void __append_node(int& rt_x, int y, int u) {
= find_min_or_max(rt_x, true);
rt_x (y) = rs(y) = 0;
ls[y] = u;
ori[y].tag = tag_non_tree[y].tag = 0;
tag_tree[y] = 1;
subtree_size(rt_x, y);
__concat}
inline void append_node(int& rt_x, int u) {
(rt_x, new_node(), u);
__append_node}
// aAuBa, a is the original root
// Return the splay root(Not the tree root)
int make_root(int u) {
int x = node[u].begin()->second; // Any occurrence
(x);
splayint y = __find_min_or_max(x, false);
if (ori[y] == u)
return x; // Already root
[ls(x)] = 0;
fa(x) = 0;
ls[u][0] = x;
node// pushup(x);
// y: aA, x: uBa
(y);
splay[ori[y]].erase(0);
nodeint tmp = y;
= rs(y);
y // y: A
if (y) {
[y] = 0;
fa(x, y);
concat}
// x: uBaA
(x, tmp);
reassign_representative(x, tmp, u);
__append_node// x: uBaAu
return x;
}
void init(int n) {
for (int i = 1; i <= n; ++i) {
int x = new_node();
(x) = rs(x) = fa[x] = 0;
ls[x] = i;
ori[i][0] = x;
node[i] = x;
representative[x] = 1;
subtree_size}
}
inline void access(int x) {
(x);
splay}
int find_root(int x) {
// If not splay, the complexity is definitely wrong.
// Suppose it is a chain, and we always find_root(last_node)
(x);
splayreturn find_min_or_max(x, false);
}
void link_new(int u, int v) {
int x = node[u].begin()->second; // Any occurrence
int y = make_root(v);
(y, u);
append_node(x);
splayint x2 = rs(x);
= find_min_or_max(y, false);
y [ori[y]].erase(0);
node(x, y);
__concatif (x2) {
[x2] = 0;
fa(x, x2);
concat}
}
void cut_existing(int u, int v) {
(u); // To make sure that u is the father of v
make_rootint uv = node[v][u];
[v].erase(u);
node[v][0] = uv;
nodeauto vu = node[u][v];
[u].erase(v);
node(vu);
splay(uv, vu);
splayint x = ls(uv);
[x] = 0;
fa(uv) = 0;
ls(uv); // Necessary?
pushup[uv] = 0;
fa// ls(vu) = 0;
int y = rs(vu);
if (y) {
[y] = 0;
fa// rs(vu) = 0;
(x, y);
concat}
(x, vu);
reassign_representative(vu);
del_node}
bool is_connected(int u, int v) {
if (u == v)
return true;
int x = node[u].begin()->second;
(x);
splayint y = node[v].begin()->second;
(y);
splayreturn fa[x] == y || fa[fa[x]] == y;
}
};
struct DynamicConnectivity {
[MAX_LEVEL];
ETT F<int, unordered_map<int, int> > level;
unordered_mapvoid init(int n) {
for (int i = 0; (1 << i) <= n; ++i)
[i].init(n);
F}
// Assume no duplicate edge
void link_new(int u, int v) {
[u][v] = 0;
level[v][u] = 0;
levelif (F[0].is_connected(u, v)) {
[0].add_directed_edge(F[0].tag_non_tree, v, u);
F[0].add_directed_edge(F[0].tag_non_tree, u, v);
F} else {
[0].new_tree_edge(u, v);
F}
}
bool reconnect(int u, int v, int l) {
int x = F[l].node[u].begin()->second;
int y = F[l].node[v].begin()->second;
[l].access(x);
F[l].access(y);
Fif (F[l].subtree_size[x] > F[l].subtree_size[y])
(x, y);
swapwhile (1) {
[l].access(x);
Fint xx = F[l].tag_tree[x].tag;
if (xx == 0)
break;
int u = F[l].ori[xx];
auto tmp = F[l].take_out_edges(F[l].tag_tree, xx);
for (int v : tmp) {
[l].delete_directed_edge(F[l].tag_tree, v, u);
F[l+1].new_tree_edge(u, v);
F++level[u][v];
++level[v][u];
}
}
= F[l].find_root(y);
y while (1) {
[l].access(x);
Fint xx = F[l].tag_non_tree[x].tag;
if (xx == 0)
break;
auto tmp = F[l].take_out_edges(F[l].tag_non_tree, xx);
int u = F[l].ori[xx];
do {
auto it = tmp.begin();
int v = *it;
int yy = F[l].node[v].begin()->second;
.erase(it);
tmp[l].delete_directed_edge(F[l].tag_non_tree, v, u);
Fif (F[l].find_root(yy) == y) {
if (!tmp.empty())
[l].give_edges(F[l].tag_non_tree, xx, std::move(tmp));
Ffor (int i = 0; i < l; ++i)
[i].link_new(u, v);
F[l].new_tree_edge(u, v);
Freturn true;
} else {
[l+1].add_directed_edge(F[l+1].tag_non_tree, u, v);
F[l+1].add_directed_edge(F[l+1].tag_non_tree, v, u);
F++level[u][v];
++level[v][u];
}
} while (!tmp.empty());
};
return false;
}
void cut_existing(int u, int v) {
auto it1 = level[u].find(v);
int l = it1->second;
[u].erase(it1);
level[v].erase(u);
level
auto& s = F[l].tag_non_tree[F[l].representative[u]].edges;
if (s.find(v) != s.end()) {
[l].delete_directed_edge(F[l].tag_non_tree, u, v);
F[l].delete_directed_edge(F[l].tag_non_tree, v, u);
Freturn;
}
[l].delete_directed_edge(F[l].tag_tree, u, v);
F[l].delete_directed_edge(F[l].tag_tree, v, u);
Ffor (int i = 0; i <= l; ++i)
[i].cut_existing(u, v);
Fwhile (1) {
if (reconnect(u, v, l))
break;
if (l == 0)
break;
--l;
}
}
bool is_connected(int u, int v) {
return F[0].is_connected(u, v);
}
};
int main() {
int n, m;
static DynamicConnectivity dc;
("%d%d", &n, &m);
scanf.init(n);
dcint last = 0;
while (m--) {
int op, x, y;
("%d%d%d", &op, &x, &y);
scanf^= last;
x ^= last;
y switch (op) {
case 0:
.link_new(x, y);
dcbreak;
case 1:
.cut_existing(x, y);
dcbreak;
case 2:
if (dc.is_connected(x, y)) {
("Y");
puts= x;
last } else {
("N");
puts= y;
last }
break;
}
}
return 0;
}
但是只能跑到94分,第11个测试点TLE了。。。之后有空的话再试试用struct
来保存点的信息,看看能不能提高cache命中率。