BZOJ3514 GERALD07 题解
题面
个点 条边的无向图,询问保留图中编号在 的边的时候图中的联通块个数。
传送门
题解
首先考虑暴力。从 到 枚举每条边,若当前两点已连通,则不计数;否则将连通块数量-1。另一种方法是迭代地统计连接两不连通点的边出现次数 ,则答案为 。用并查集维护即可。
考虑对其优化。从 到 枚举每条边 ,若当前两点已连通,则删去环上出现时间最早的边,并记录其出现的时间为 。否则 。则 为 到 中 值小于 的数的个数。
证明。在环上,删除出现时间为 的边即可重新形成树结构,若 ,则从 开始加边时一定不会加入 边。相当于 ++。否则 显然不能加。证毕。
以上操作可以用LCT实现。
之后,问题只剩下求 区间内小于 的数的个数。而此题强制在线,那么要用树套树/主席树实现。
但本蒟蒻还没学主席树,且树套树空间开不下……于是只能用离线的二维偏序拿部分分了。
Code
#include<cstdio>
#include<algorithm>
#include<vector>
using namespace std;
const int N = 2e5 + 5;
int n, m, mq, type, ans[N];
int fa[N], v[N << 1], stack[N << 1], top;
vector<int> r[N];
struct Tree {int l, r, sum;} tr[N << 2];
struct Edge {int x, y;} e[N];
struct Node {int s[2], p, dat, rev;} t[N << 1];
struct Qry {
int id, l, r;
bool operator <(const Qry &o) const {
return l < o.l;
}
} q[N];
int read() {
int x = 0; char c = getchar();
while (c < '0' || c > '9') c = getchar();
while (c >= '0' && c <= '9') {x = (x << 3) + (x << 1) + (c ^ 48); c = getchar();}
return x;
}
int get(int x) {
if (x == fa[x]) return x;
return fa[x] = get(fa[x]);
}
bool isroot(int x) {
return t[t[x].p].s[0] != x && t[t[x].p].s[1] != x;
}
void pushup(int x) {
t[x].dat = x;
for (int i = 0; i < 2; i++)
if (t[x].s[i] && v[t[t[x].s[i]].dat] < v[t[x].dat])
t[x].dat = t[t[x].s[i]].dat;
}
void pushrev(int x) {
swap(t[x].s[0], t[x].s[1]); t[x].rev ^= 1;
}
void pushdown(int x) {
if (!t[x].rev) return ;
pushrev(t[x].s[0]); pushrev(t[x].s[1]); t[x].rev = 0;
}
void rotate(int x) {
int y = t[x].p, z = t[y].p, k = t[y].s[1] == x;
if (!isroot(y)) t[z].s[t[z].s[1] == y] = x; t[x].p = z;
t[y].s[k] = t[x].s[k ^ 1]; t[t[x].s[k ^ 1]].p = y;
t[x].s[k ^ 1] = y; t[y].p = x;
pushup(y); pushup(x);
}
void splay(int x) {
int p = x;
stack[++top] = p;
while (!isroot(p)) stack[++top] = p = t[p].p;
while (top) pushdown(stack[top--]);
while (!isroot(x)) {
int y = t[x].p, z = t[y].p;
if (!isroot(y))
if (t[z].s[1] == y ^ t[y].s[1] == x) rotate(x);
else rotate(y);
rotate(x);
}
}
void access(int x) {
int z = x;
for (int y = 0; x; y = x, x = t[x].p) {
splay(x); t[x].s[1] = y; pushup(x);
}
splay(z);
}
void makeroot(int x) {
access(x); pushrev(x);
}
int findroot(int x) {
access(x);
while (t[x].s[0]) {
pushdown(x); x = t[x].s[0];
}
splay(x);
return x;
}
void split(int x, int y) {
makeroot(x); access(y);
}
void link(int x, int y) {
makeroot(x); t[x].p = y;
}
void cut(int x, int y) {
makeroot(x);
if (findroot(y) == x && t[x].s[1] == y && !t[y].s[0]) {
t[x].s[1] = t[y].p = 0; pushup(x);
}
}
void Build(int l, int r, int x) {
tr[x].l = l; tr[x].r = r;
if (l == r) return ;
int mid = l + r >> 1;
Build(l, mid, x << 1); Build(mid + 1, r, x << 1 | 1);
}
void Insert(int p, int x) {
tr[x].sum++;
if (tr[x].l == tr[x].r) return ;
int mid = tr[x].l + tr[x].r >> 1;
if (p <= mid) Insert(p, x << 1);
else Insert(p, x << 1 | 1);
}
int Query(int l, int r, int x) {
if (l <= tr[x].l && tr[x].r <= r) return tr[x].sum;
int mid = tr[x].l + tr[x].r >> 1, res = 0;
if (l <= mid) res += Query(l, r, x << 1);
if (r > mid) res += Query(l, r, x << 1 | 1);
return res;
}
int main() {
n = read(); m = read(); mq = read(); type = read();
for (int i = 1; i <= n; i++) {
v[i] = 0x7fffffff; fa[i] = i;
}
for (int i = 1; i <= n + m; i++) t[i].dat = i;
for (int i = 1; i <= m; i++) {
int x = read(), y = read();
e[i] = (Edge){x, y};
v[i + n] = i;
if (x == y) {
r[i].push_back(i); continue;
}
if (get(x) != get(y)) {
link(x, i + n); link(y, i + n); fa[get(x)] = get(y); r[0].push_back(i);
}
else {
split(x, y);
int p = t[y].dat;
r[v[p]].push_back(i);
cut(e[p - n].x, p); cut(e[p - n].y, p);
link(x, i + n); link(y, i + n);
}
}
for (int i = 1; i <= mq; i++) q[i] = (Qry){i, read(), read()};
sort(q + 1, q + mq + 1);
Build(1, m, 1);
for (int i = 0, j = 1; i <= m; i++) {
while (j <= mq && q[j].l == i) {
ans[q[j].id] = Query(q[j].l, q[j].r, 1); j++;
}
for (int j = 0; j < r[i].size(); j++) Insert(r[i][j], 1);
}
for (int i = 1; i <= mq; i++) printf("%d\n", n - ans[i]);
return 0;
}
本文作者:realFish的博客
本文链接:https://www.cnblogs.com/fish07/p/16179210.html
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步