[LOJ#121]动态图连通性

试题描述

这是一道模板题。

你要维护一张无向简单图。你被要求加入删除一条边及查询两个点是否连通。

  • 0:加入一条边。保证它不存在。
  • 1:删除一条边。保证它存在。
  • 2:查询两个点是否联通。

输入

输入的第一行是两个数 N M。N=5000,M≤500000。

接下来 M 行,每一行三个数 op x y。 op 表示操作编号。

输出

对于每一个 op=2 的询问,输出一行 Y 或 N ,表示两个节点是否连通。

输入示例1


输出示例1

N
Y
N

输入示例2


输出示例2

N
Y
Y
N

数据规模及约定

对于数据点 1,N≤200,M≤200

对于数据点 2,N=5,M≤30

对于数据点 3,N=10,M≤1000,其中查询的次数 >=900 次。

对于数据点 4,N=300,M≤50000

对于数据点 5,N=5000,M≤200000,没有操作 1,其中约70是操作2。

对于数据点 6,N=5000,M≤200000,没有操作 1,其中约70是操作0。

对于数据点 7、8,N=100,M≤500000

对于数据点 9,N=5000,M≤500000,图是一棵树,其直径 ≤6 。

对于数据点 10, N=5000,M≤500000,图是一棵树,其每个点度数 ≤4 。

P.S. 其实 9 是菊花,10 是单链,而没有放随机树的点...

题解

动态树模板练习。(离线,维护删除时间最大生成树)

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cctype>
#include <algorithm>
using namespace std; const int BufferSize = 1 << 16;
char buffer[BufferSize], *Head, *Tail;
inline char Getchar() {
if(Head == Tail) {
int l = fread(buffer, 1, BufferSize, stdin);
Tail = (Head = buffer) + l;
}
return *Head++;
}
int read() {
int x = 0, f = 1; char c = Getchar();
while(!isdigit(c)){ if(c == '-') f = -1; c = Getchar(); }
while(isdigit(c)){ x = x * 10 + c - '0'; c = Getchar(); }
return x * f;
} #define maxn 505010
#define oo 2147483647 struct Node {
int siz, tim, mni;
bool rev;
Node(): rev(0) {}
Node(int _): tim(_) {}
};
struct LCT {
Node ns[maxn];
int ch[maxn][2], fa[maxn];
int S[maxn], top;
int _siz, _mni; bool isrt(int u) { return !fa[u] || (ch[fa[u]][0] != u && ch[fa[u]][1] != u); }
void pushdown(int o) {
if(!ns[o].rev) return ;
swap(ch[o][0], ch[o][1]);
for(int i = 0; i < 2; i++) if(ch[o][i]) ns[ch[o][i]].rev ^= 1;
ns[o].rev = 0;
return ;
}
void maintain(int o) {
ns[o].siz = 1; ns[o].mni = o;
for(int i = 0; i < 2; i++) if(ch[o][i]) {
ns[o].siz += ns[ch[o][i]].siz;
int& tmp = ns[o].mni;
if(ns[tmp].tim > ns[ns[ch[o][i]].mni].tim) tmp = ns[ch[o][i]].mni;
}
return ;
}
void rotate(int u) {
int y = fa[u], z = fa[y], l = 0, r = 1;
if(!isrt(y)) ch[z][ch[z][1]==y] = u;
if(ch[y][1] == u) swap(l, r);
fa[u] = z; fa[y] = u; fa[ch[u][r]] = y;
ch[y][l] = ch[u][r]; ch[u][r] = y;
maintain(y);
return ;
}
void splay(int u) {
int t = u; S[top = 1] = t;
while(!isrt(t)) S[++top] = fa[t], t = fa[t];
while(top) pushdown(S[top--]);
while(!isrt(u)) {
int y = fa[u], z = fa[y];
if(!isrt(y)) {
if(ch[y][0] == u ^ ch[z][0] == y) rotate(u);
else rotate(y);
}
rotate(u);
}
return maintain(u);
}
void access(int u) {
splay(u); ch[u][1] = 0; maintain(u);
while(fa[u]) splay(fa[u]), ch[fa[u]][1] = u, maintain(fa[u]), splay(u);
return ;
}
void makert(int u) {
access(u); ns[u].rev ^= 1;
return ;
}
void link(int a, int b) {
// printf("link(%d, %d)\n", a, b);
makert(b); fa[b] = a;
return ;
}
void cut(int a, int b) {
// printf("cut(%d, %d)\n", a, b);
makert(a); access(b); ch[b][0] = fa[a] = 0;
return maintain(b);
}
void query(int a, int b) {
// printf("query(%d, %d)\n", a, b);
makert(b); access(a);
_siz = ns[a].siz; _mni = ns[a].mni;
return ;
}
bool together(int a, int b) {
// printf("together(%d, %d)\n", a, b);
if(a == b) return 1;
makert(b); access(a);
bool ok = 0;
while(ch[a][0]) {
a = ch[a][0];
if(a == b){ ok = 1; break; }
}
splay(a);
return ok;
}
} sol; #define pii pair <int, int>
#define x first
#define y second
#define mp(x, y) make_pair(x, y) struct Que {
int tp, a, b, e;
Que() {}
Que(int _1, int _2, int _3): tp(_1), a(_2), b(_3) {}
} qs[maxn];
pii edges[maxn];
int uid[25010010];
int lstdel[maxn], cntn; int code(pii e) { return e.x * 5001 + e.y; } int main() {
int n = cntn = read(), m = read();
for(int i = 1; i <= m; i++) {
int tp = read(), a = read(), b = read();
if(a > b) swap(a, b);
qs[i] = Que(tp, a, b);
} for(int i = m; i; i--) {
int tp = qs[i].tp, a = qs[i].a, b = qs[i].b;
if(tp == 1) {
pii e = mp(a, b);
lstdel[qs[i].e = uid[code(e)] = ++cntn] = i;
edges[cntn] = e;
}
if(tp == 0) {
pii e = mp(a, b);
if(uid[code(e)]) qs[i].e = uid[code(e)], uid[code(e)] = 0;
else lstdel[qs[i].e = ++cntn] = m + 1, edges[cntn] = e;
}
}
for(int i = 1; i <= n; i++) sol.ns[i] = Node(oo);
for(int i = n + 1; i <= cntn; i++) sol.ns[i] = Node(lstdel[i]); for(int i = 1; i <= m; i++) {
int tp = qs[i].tp, a = qs[i].a, b = qs[i].b, e = qs[i].e;
if(tp == 0) {
if(!sol.together(a, b)) sol.link(a, e), sol.link(e, b);
else {
sol.query(a, b);
if(lstdel[sol._mni] < lstdel[e]) {
sol.cut(edges[sol._mni].x, sol._mni);
sol.cut(sol._mni, edges[sol._mni].y);
sol.link(a, e); sol.link(e, b);
}
}
}
if(tp == 1) {
sol.query(a, b);
if(sol._siz == 3) sol.cut(a, e), sol.cut(b, e);
}
if(tp == 2) puts(sol.together(a, b) ? "Y" : "N");
} return 0;
}

[LOJ#121]动态图连通性的更多相关文章

  1. 【LOJ121】「离线可过」动态图连通性

    [LOJ121]「离线可过」动态图连通性 题面 LOJ 题解 线段树分治的经典应用 可以发现每个边出现的时间是一个区间 而我们每个询问是一个点 所以我们将所有边的区间打到一颗线段树上面去 询问每个叶子 ...

  2. LOJ121 「离线可过」动态图连通性

    思路 动态图连通性的板子,可惜我不会在线算法 离线可以使用线段树分治,每个边按照存在的时间插入线段树的对应节点中,最后再dfs一下求出解即可,注意并查集按秩合并可以支持撤销操作 由于大量使用STL跑的 ...

  3. LOJ 121 「离线可过」动态图连通性——LCT维护删除时间最大生成树 / 线段树分治

    题目:https://loj.ac/problem/121 离线,LCT维护删除时间最大生成树即可.注意没有被删的边的删除时间是 m+1 . 回收删掉的边的节点的话,空间就可以只开 n*2 了. #i ...

  4. LOJ.121.[离线可过]动态图连通性(线段树分治 按秩合并)

    题目链接 以时间为下标建线段树.线段树每个节点开个vector. 对每条边在其出现时间内加入线段树,即,把这条边按时间放在线段树的对应区间上,会影响\(O(\log n)\)个节点. 询问就放在线段树 ...

  5. LOJ#121. 「离线可过」动态图连通性(线段树分治)

    题意 板子题,题意很清楚吧.. Sol 很显然可以直接上LCT.. 但是这题允许离线,于是就有了一个非常巧妙的离线的做法,好像叫什么线段树分治?? 此题中每条边出现的位置都可以看做是一段区间. 我们用 ...

  6. LOJ #121. 「离线可过」动态图连通性 LCT维护最大生成树

    这个还是比较好理解的. 你考虑如果所有边构成一棵树的话直接用 LCT 模拟一波操作就行. 但是可能会出现环,于是我们就将插入/删除操作按照时间排序,然后依次进行. 那么,我们就要对我们维护的生成树改变 ...

  7. 【LOJ】#121. 「离线可过」动态图连通性

    题解 和BZOJ4025挺像的 就是维护边权是时间的最大生成树 删边直接删 两点未联通时直接相连,两点联通则找两点间边权小的一条边删除即可 代码 #include <bits/stdc++.h& ...

  8. loj#121.「离线可过」动态图连通性

    题面 话说#122怎么做啊 题解 我的\(\mathrm{LCT}\)水平极差,连最小生成树都快忘了,赶紧复习一下 做法和这篇是一样的 这道题还可以练习线段树分治 还可以练习ETT 果然是道吼题 代码 ...

  9. 「LOJ 121」「离线可过」动态图连通性「按时间分治 」「并查集」

    题意 你要维护一张\(n\)个点的无向简单图.你被要求执行\(m\)条操作,加入删除一条边及查询两个点是否连通. 0:加入一条边.保证它不存在. 1:删除一条边.保证它存在. 2:查询两个点是否联通. ...

随机推荐

  1. 10款免费的MySQL数据库图形化管理工具

    绝大多数的关系数据库都明显不同于MS Access,它们都有两个截然不同的部分:后端作为数据仓库,前端作为用于数据组件通信的用户界面.这种设计非常巧妙,它并行处理两层编程模型,将数据 层从用户界面中分 ...

  2. HDU 4284 Travel (Folyd预处理+dfs暴搜)

    题意:给你一些N个点,M条边,走每条边要花费金钱,然后给出其中必须访问的点,在这些点可以打工,但是需要先拿到证书,只可以打一次,也可以选择不打工之直接经过它.一个人从1号点出发,给出初始金钱,问你能不 ...

  3. java,求1-100以内所有偶数的和。

    package study01; public class Even { public static void main(String[] args) { int sum = 0; for (int ...

  4. vue-awesome-swiper插件爬坑

    最近自己在做一个基于vue的知乎的移动端单页面,遇到很多坑,先说一下遇到最大的坑,其实并不推荐使用 vue-awesome-swiper,如果项目应用轮播,切换少的话.言归正传,现在来介绍vue-aw ...

  5. CentOS 系统下Gitlab搭建与基本配置 以及代码备份迁移过程

    GitLab 是一个开源的版本管理系统,提供了类似于 GitHub 的源代码浏览,管理缺陷和注释等功能,你可以将代码免费托管到 GitLab.com,而且不限项目数量和成员数.最吸引人的一点是,可以在 ...

  6. 学习路由器vue-router

    vue-router:vue官方路由管理器. 功能:嵌套的路由/视图表模块化的.基于组件的路由配置路由参数.查询.通配符基于 Vue.js 过渡系统的视图过渡效果细粒度的导航控制带有自动激活的 CSS ...

  7. 记一次低级错误导致的mysql(111)

    今天下午配好的双主多从服务器,两台主机+主机内安装好的6台虚拟机,两台Mysql master各授权好其slave的远程登录,原本好端端的能远程登录,晚上回来时候就发现其中一台master登录不上其s ...

  8. 基于网站地址URL传输session信息

    在php的学习中,会话是我们常常用到的,那今天我们就来详细讲讲会话中的session: 一.session的工作机制:当开启session后,服务器会在服务器中保存session文件,然后再浏览器保存 ...

  9. python基础-面向对象的三大特征

    继承 单继承 父类 基类 子类 派生类 继承:是面向对象软件技术当中的一个概念,如果一个类别A“继承自”另一个类别B,就把这个A称为“B的子类别”,而把B称为“A的父类别”也可以称“B是A的超类”. ...

  10. Python3 S.join() 个人笔记

    S.join(iterable) S:需要的分隔符 iterable:被分割对象 . 注意括号里必须只能有一个成员,比如 ','.join('a','b') 这种写法是行不通的 实例:'-'.join ...