题意

板子题,题意很清楚吧。。

Sol

很显然可以直接上LCT。。

但是这题允许离线,于是就有了一个非常巧妙的离线的做法,好像叫什么线段树分治??

此题中每条边出现的位置都可以看做是一段区间。

我们用线段树维护。线段树的每个节点维护一个vector表示覆盖了当前节点的边的存在区间

因为总的边数是$M$的,因此线段树内总的元素最多为$logM * M$,空间可以保证

输出答案的话需要最后dfs一遍

用并查集维护出当前联通的点,需要支持撤销操作。

方法是通过按秩合并保证复杂度,不带路径压缩。

这样的话每次断父亲就行了。

我看题解里面的按秩合并都是按度数合并的,我试了一下按节点大小合并,发现跑的差不多快。。

/*
线段树分治
对于维护每一个操作出现的区间
并查集维护连通性,维护的时候记录度数,按秩合并
撤销的时候把度数小的撤销掉。
*/
#include<cstdio>
#include<vector>
using namespace std;
const int MAXN = * 1e6 + ;
inline int read() {
char c = getchar(); int x = , f = ;
while(c < '' || c > '') {if(c == '-') f = -; c = getchar();}
while(c >= '' && c <= '') x = x * + c - '', c = getchar();
return x * f;
}
int N, M;
int tim[][];//边(i, j)加入的时间
int fa[MAXN];
struct Node {
int x, deg;
}S[MAXN];
struct Query {
int opt, x, y;
}Q[MAXN];
#define ls k << 1
#define rs k << 1 | 1
struct SegTree {
int l, r;
vector<int> id;
}T[MAXN];
void Build(int k, int ll, int rr) {
T[k] = (SegTree) {ll, rr};
if(ll == rr) return ;
int mid = ll + rr >> ;
Build(ls, ll, mid); Build(rs, mid + , rr);
}
void IntervalAdd(int k, int ll, int rr, int val) {
if(ll <= T[k].l && T[k].r <= rr) {T[k].id.push_back(val); return ;}
int mid = T[k].l + T[k].r >> ;
if(ll <= mid)IntervalAdd(ls, ll, rr, val);
if(rr > mid)IntervalAdd(rs, ll, rr, val);
}
int Top, inder[MAXN];
int find(int x) {
if(fa[x] == x) return x;
else return find(fa[x]);
}
void unionn(int x, int y) {
x = find(x); y = find(y);
if(x == y) return;
if(inder[x] < inder[y]) swap(x, y);
fa[y] = x;
S[++Top] = (Node) {y, inder[y]};
if(inder[x] == inder[y]) S[++Top] = (Node) {x, inder[x] = inder[x] + inder[y]};//tag
}
void Delet(int cur) {
while(Top > cur) {
Node pre = S[Top--];
fa[pre.x] = pre.x;
inder[pre.x] = pre.deg;
}
}
void dfs(int k) {
int cur = Top;
for(int i = ; i < T[k].id.size(); i++) unionn(Q[T[k].id[i]].x, Q[T[k].id[i]].y);
if(T[k].l == T[k].r) {
if(Q[T[k].l].opt == )
putchar(find(Q[T[k].l].x) == find(Q[T[k].l].y) ? 'Y' : 'N'), putchar('\n');
} else dfs(ls), dfs(rs); Delet(cur);
}
int main() {
N = read(); M = read();
for(int i = ; i <= N; i++) fa[i] = i, inder[i] = ;
Build(, , M);//按时间为下标建线段树
for(int i = ; i <= M; i++) {
int opt = read(), x = read(), y = read();
if(x > y) swap(x, y);
if(opt == ) tim[x][y] = i;
if(opt == ) IntervalAdd(, tim[x][y], i, i), tim[x][y] = ;
Q[i] = (Query) {opt, x, y};
}
for(int i = ; i <= N; i++)
for(int j = i; j <= N; j++)
if(tim[i][j])
IntervalAdd(, tim[i][j], M, tim[i][j]);
dfs();
return ;
}

LOJ#121. 「离线可过」动态图连通性(线段树分治)的更多相关文章

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

  9. 「POI2011 R2 Day2」Tree Rotations【线段树合并】

    题目链接 [BZOJ] [洛谷] [LOJ] 题解 由于是前序遍历,那么讨论一棵树上的逆序对的情况. 两个节点都在左子树上 两个节点都在右子树上 两个节点分别在不同的子树上. 前两种情况其实也可以归结 ...

随机推荐

  1. android user用户版本提高adb权限【转】

    本文转载自:http://blog.csdn.net/liyongming1982/article/details/14108111 有的user用户版本的log 不全,且push/pull某些文件或 ...

  2. 【Maven】pom.xml(1)

    在pom.xml加入: <build> <finalName>oauth2</finalName> <resources> <resource&g ...

  3. 黑客技术 —— Linux 命令行

    很多和正则表达式 re 是一致的: 1. 修改上次执行的命令 删除多余部分: % grep fooo /var/log/auth.log % ^o % grep foo /var/log/auth.l ...

  4. Opencv中视频播放与进度控制

    视频画面本质上是由一帧一帧的连续图像组成的,播放视频其实就是在播放窗口把一系列连续图像按一定的时间间隔一幅幅贴上去实现的. 人眼在连续图像的刷新最少达到每秒24帧的时候,就分辨不出来图像间的闪动了,使 ...

  5. 「NOIP2014」「LuoguP2296」 寻找道路

    Description 在有向图 G 中,每条边的长度均为 1 ,现给定起点和终点,请你在图中找一条从起点到终点的路径,该路径满足以下条件: 路径上的所有点的出边所指向的点都直接或间接与终点连通. 在 ...

  6. UVA140 剪枝

    题目 分析:这个题的数据范围很小,直接打印全排列去判断也能过,但是这里存在两个剪枝,第一个,如果当前的距离已经大于前面距离的最小值,则剪枝,还有一个就是如果与当前结点相连的边数大于等于前面距离的最小值 ...

  7. MySql数据库知识点

    关系型数据库管理系统简介 为什么使用数据库 1.降低存储数据的冗余度 2.更高的数据一致性 3.存储的数据可以共享 4.可以建立数据库所遵循的标准 5.便于维护数据完整性 6.能够实现数据的安全性 数 ...

  8. printf(“%06d\n”,x);

    %06d : %是格式化输入接受参数的标记 0格式化命令:结果将用零来填充 6:填充位数 d:代表十进制 数据 printf(“%06d\n”,x); console: 000001 000002 0 ...

  9. ASP.NET Core MVC 2.x 全面教程_ASP.NET Core MVC 21. Model 验证 Again

    深入的将Model验证 手动添加验证的错误 view里面显示每个属性的验证错误信息 显示整个model级别错误 自定义验证 如果业务逻辑需要比较复杂的验证.而且这个验证逻辑可能到处复用的话就应该考虑使 ...

  10. BZOJ2217:Lollipop

    题意 给定一个由1和2组成的序列,多次询问是否存在一个区间满足区间和=x 分析 结论:假如存在一个子串和为x,那么一定存在一个前缀,和为x或x+1 证明:可以认为原串是由和为x的串在开头和结尾添加若干 ...