【splay】【P9358】 Bridge
【splay】【P9358】 Bridge
Analysis
以下是赛时的思考过程。
我们把从某个城市的
一个观察是,起点和终点总是一一对应的。换句话说,一个起点对应唯一一个终点,而一个终点也唯一对应一个起点。进一步画图可以发现,添加一座桥其实相当于交换两个路径的起点对应的的终点。如图:
图中标有相同字母的两个结点对应一组配对的起终点。
不妨假定这个结论是对的,我们将在下面给出维护方法后自然地发现这个结论的正确性。这个观察直接启示我们尝试把每条路径都维护出来。显然每条路径都是一条由结点构成的链,添加一座桥“大致”就相当于交换两条路径的后半部分。这个东西大致可以用 splay 做。之所以是“大致”,是因为添加一座桥以后,桥连接的两个结点将同时存在于两条路径上。这个结构不是很能方便地用 splay 维护出来,我们更希望每个点唯一地对应一条路径。
观察添加一座桥连接
对于一次从
最后一个问题是,一共有
初始时,splay 只有
最后是经典结论,多个总节点数为
Code
#include <map>
#include <iostream>
const int maxn = 100005;
struct Node {
Node *fa, *ch[2];
int bel;
Node():fa(nullptr), bel(0) {
ch[0] = ch[1] = nullptr;
}
inline int getRela(Node *u) {
return fa->ch[1] == u;
}
void rotate(int x) {
auto nt = ch[x];
ch[x] = nt->ch[x ^ 1];
nt->ch[x ^ 1] = this;
if (fa) fa->ch[getRela(this)] = nt;
nt->fa = fa;
fa = nt;
if (ch[x]) ch[x]->fa = this;
}
void splay() {
while (fa != nullptr) {
auto pa = fa->fa;
if (pa == nullptr) {
fa->rotate(getRela(this));
} else {
int x1 = getRela(this), x2 = fa->getRela(fa);
if (x1 == x2) {
pa->rotate(x1);
fa->rotate(x2);
} else {
fa->rotate(x1);
}
}
}
}
};
int n, m, q;
std::map<int, Node*> node[maxn];
int main() {
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
std::cin >> n >> m >> q;
for (int i = 1; i <= n; ++i) {
auto p = new Node();
p->bel = i;
node[i][m + 1] = p;
}
for (int op, a, b; q; --q) {
std::cin >> op >> a;
if (op == 1) {
std::cin >> b;
auto p1 = node[a].lower_bound(b), p2 = node[a + 1].lower_bound(b);
auto A = p1->second, B = p2->second;
A->splay(); B->splay();
auto p3 = new Node, p4 = new Node;
p3->bel = A->bel;
p4->bel = B->bel;
if ((p3->ch[1] = A->ch[1])) {
p3->ch[1]->fa = p3;
}
if ((p4->ch[1] = B->ch[1])) {
p4->ch[1]->fa = p4;
}
A->ch[1] = p4;
B->ch[1] = p3;
p3->fa = B; p4->fa = A;
node[a][p1->first] = p3;
node[a + 1][p2->first] = p4;
node[a][b] = A;
node[a + 1][b] = B;
} else {
auto u = node[a].begin()->second;
u->splay();
while (u->ch[1]) u = u->ch[1];
std::cout << u->bel << '\n';
u->splay();
}
}
}