题目链接

以时间为下标建线段树。线段树每个节点开个vector。

对每条边在其出现时间内加入线段树,即,把这条边按时间放在线段树的对应区间上,会影响\(O(\log n)\)个节点。

询问就放在线段树的对应叶子节点上。

然后对整棵树DFS,当进入一个节点时,将这个点代表的这段区间中出现的边全部加到图里,即合并起来,之后在离开这个点时撤销。

可以用不路径压缩、按秩合并的并查集维护连通性。这样就可以撤销了。

合并时用栈记录合并前状态,合并前的父节点用\(x\)或是\(fa[x]\)都行,因为合并的时候是合并集合根节点,用\(x\)还是\(fa[x]\)都一样。。

如果秩改变也要加入栈。

启发式合并按深度还是按size无所谓。

//1548ms	48256K
#include <map>
#include <cstdio>
#include <cctype>
#include <vector>
#include <algorithm>
#define mp std::make_pair
#define pr std::pair<int,int>
#define Vec std::vector<int>
//#define gc() getchar()
#define MAXIN 500000
#define gc() (SS==TT&&(TT=(SS=IN)+fread(IN,1,MAXIN,stdin),SS==TT)?EOF:*SS++)
const int N=5005,M=5e5+5; int n,m,fa[N],dep[N],top;
std::map<pr,int> las;
char IN[MAXIN],*SS=IN,*TT=IN;
struct Node
{
int x,dep;
}sk[M<<1];//M就够吧。。
struct Operation
{
int id,u,v;
}opt[M];
struct Segment_Tree
{
#define lson rt<<1
#define rson rt<<1|1
std::vector<int> vec[M<<2];
void Update(int l,int r,int rt,int L,int R,int id)
{
if(L<=l && r<=R) return (void)vec[rt].push_back(id);
int m=l+r>>1;
if(L<=m) Update(l,m,rt<<1,L,R,id);
if(m<R) Update(m+1,r,rt<<1|1,L,R,id);
}
}T; inline int read()
{
int now=0;register char c=gc();
for(;!isdigit(c);c=gc());
for(;isdigit(c);now=now*10+c-'0',c=gc());
return now;
}
int Get_fa(int x){
return x==fa[x]?x:Get_fa(fa[x]);
}
inline void Merge(int x,int y)
{
if((x=Get_fa(x))==(y=Get_fa(y))) return;
if(dep[y]>dep[x]) std::swap(x,y);//y->x
fa[y]=x, sk[++top]=(Node){y,dep[y]};
if(dep[x]==dep[y]) sk[++top]=(Node){x,dep[x]++};
}
inline void Delete(int bef)
{
while(top>bef)
{
int x=sk[top].x;
fa[x]=x, dep[x]=sk[top--].dep;
}
}
void DFS(int l,int r,int rt)
{
int now=top;
const Vec &v=T.vec[rt];
for(int i=0,lim=v.size(); i<lim; ++i) Merge(opt[v[i]].u,opt[v[i]].v);
if(l==r){
if(opt[l].id==2)//询问直接在叶节点上
putchar(Get_fa(opt[l].u)==Get_fa(opt[l].v)?'Y':'N'),putchar('\n');
}
else DFS(l,l+r>>1,lson), DFS((l+r>>1)+1,r,rson);
Delete(now);
} int main()
{
n=read(), m=read();
for(int i=1; i<=n; ++i) fa[i]=i;
std::map<pr,int>::iterator it;
for(int id,x,y,i=1; i<=m; ++i)
{
id=read(), x=read(), y=read();
if(x>y) std::swap(x,y);
if(!id) las[mp(x,y)]=i;
else if(id==1) it=las.find(mp(x,y)), T.Update(1,m,1,it->second,i,i), it->second=0;//包含不包含i无所谓了,i处已不是询问
opt[i]=(Operation){id,x,y};
}
for(it=las.begin(); it!=las.end(); ++it)
if(it->second) T.Update(1,m,1,it->second,m,it->second);
DFS(1,m,1); return 0;
}

LOJ.121.[离线可过]动态图连通性(线段树分治 按秩合并)的更多相关文章

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

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

  2. loj#2312. 「HAOI2017」八纵八横(线性基 线段树分治)

    题意 题目链接 Sol 线性基+线段树分治板子题.. 调起来有点自闭.. #include<bits/stdc++.h> #define fi first #define se secon ...

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

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

  4. [LOJ#121]动态图连通性

    [LOJ#121]动态图连通性 试题描述 这是一道模板题. 你要维护一张无向简单图.你被要求加入删除一条边及查询两个点是否连通. 0:加入一条边.保证它不存在. 1:删除一条边.保证它存在. 2:查询 ...

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

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

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

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

  7. [基本操作]线段树分治和动态dp

    不知道为什么要把这两个没什么关系的算法放到一起写...可能是都很黑科技? 1.线段树分治 例题:bzoj4026 二分图 给你一个图,资瓷加一条边,删一条边,询问当前图是不是二分图 如果用 LCT 的 ...

  8. 【离线 撤销并查集 线段树分治】bzoj1018: [SHOI2008]堵塞的交通traffic

    本题可化成更一般的问题:离线动态图询问连通性 当然可以利用它的特殊性质,采用在线线段树维护一些标记的方法 Description 有一天,由于某种穿越现象作用,你来到了传说中的小人国.小人国的布局非常 ...

  9. LOJ 2585 「APIO2018」新家 ——线段树分治+二分答案

    题目:https://loj.ac/problem/2585 算答案的时候要二分! 这样的话,就是对于询问位置 x ,二分出一个最小的 mid 使得 [ x-mid , x+mid ] 里包含所有种类 ...

随机推荐

  1. SQL中的全局变量和局部变量(@@/@)

    在SQL中,我们常常使用临时表来存储临时结果,对于结果是一个集合的情况,这种方法非常实用,但当结果仅仅是一个数据或者是几个数据时,还要去建一个表,显得就比较麻烦,另外,当一个SQL语句中的某些元素经常 ...

  2. 20155321 2016-2017-2 《Java程序设计》第五周学习总结

    20155321 2016-2017-2 <Java程序设计>第五周学习总结 教材学习内容总结 第八章 异常处理 Java提供特有的语句进行处理 try { 需要被检测的代码; } cat ...

  3. Anaconda+django写出第一个web app(七)

    今天来实现如何在页面弹出一些信息,比如注册成功后弹出注册成功的信息.这一点可以通过materialize里的Toasts来实现. django自带的messages可以告诉我们是否注册成功,以及注册失 ...

  4. 内置函数bytes()

    a=b'\x00\x9c@c' print a[3]#99,c的ascii码是99 print a[1]#156 并且byte是无法修改的 c[1]=155 Traceback (most recen ...

  5. 从xtrabackup备份恢复单表【转】

    目前对MySQL比较流行的备份方式有两种,一种上是使用自带的mysqldump,另一种是xtrabackup,对于数据时大的环境,普遍使用了xtrabackup+binlog进行全量或者增量备份,那么 ...

  6. mysql子查询 exists,not exists,all和any

    (1)实现让结果集A - 结果集B:--利用not exists,合并则可用union . exists,not exists:用于判断且获取结果集A是否存在地结果集B中! ==========结果集 ...

  7. Java基础91 mysql的用户权限设置问题

    1.概述 1)MySQL数据库中root用户具有最高的权限(超级用户),可以对任何数据库,任何表进行操作. 2)权限账户,只拥有部分权限(CRUD) .例如:只能操作某个数据库的某张表等等. 2.my ...

  8. mysql添加事件

    begin declare debug int; set @debug = 0; if @debug = 1 then insert into task_monitor(info) values('s ...

  9. json多态序列化

    https://blog.csdn.net/java_huashan/article/details/46428971 https://blog.csdn.net/bruce128/article/d ...

  10. Android studio2.3.3升级3.1.2坑

    原文:https://blog.csdn.net/qq_26361871/article/details/80255141 1.grade配置Error: Could not find com.and ...