题目:https://loj.ac/problem/121

离线,LCT维护删除时间最大生成树即可。注意没有被删的边的删除时间是 m+1 。

回收删掉的边的节点的话,空间就可以只开 n*2 了。

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<map>
#define mkp make_pair
#define ls c[x][0]
#define rs c[x][1]
using namespace std;
int rdn()
{int ret=0;bool fx=1;char ch=getchar();while(ch>'9'||ch<'0'){if(ch=='-')fx=0;ch=getchar();}while(ch>='0'&&ch<='9')ret=ret*10+ch-'0',ch=getchar();return fx?ret:-ret;
}
const int N=1e4+5,M=5e5+5;
int n,m,tot,op[M],fa[N],c[N][2],sta[N],top;
int del_pl[N],del_top;
bool rev[N];
map<pair<int,int>,int> mp;
struct Node{int x,y,t;}a[M];
struct Dt{int t,id,bh;Dt(int a=0,int b=0,int c=0):t(a),id(b),bh(c) {}
}vl[N],mn[N];
Dt Mn(Dt x,Dt y)
{if(!x.t)return y; if(!y.t)return x;return (x.t<y.t)?x:y;
}
int New()
{int ret=(del_top?del_pl[del_top--]:++tot);c[ret][0]=c[ret][1]=fa[ret]=0; return ret;
}
bool isroot(int x){return c[fa[x]][0]!=x&&c[fa[x]][1]!=x;}
void pshp(int x){mn[x]=Mn(vl[x],Mn(mn[ls],mn[rs]));}
void Rev(int x)
{if(!rev[x])return; rev[x]=0;rev[ls]^=1; rev[rs]^=1; swap(ls,rs);
}
void rotate(int x)
{int y=fa[x],z=fa[y],d=(x==c[y][1]);if(!isroot(y))c[z][y==c[z][1]]=x;fa[x]=z;fa[y]=x; fa[c[x][!d]]=y;c[y][d]=c[x][!d]; c[x][!d]=y;pshp(y); pshp(x);
}
void splay(int x)
{sta[top=1]=x;for(int k=x;!isroot(k);k=fa[k])sta[++top]=fa[k];for(int i=top;i;i--)Rev(sta[i]);while(!isroot(x)){int y=fa[x],z=fa[y];if(!isroot(y))((x==c[y][0])^(y==c[z][0]))?rotate(x):rotate(y);rotate(x);}
}
void access(int x)
{for(int t=0;x;rs=t,pshp(x),t=x,x=fa[x])splay(x);
}
void mkrt(int x)
{access(x);splay(x);rev[x]^=1;
}
void link(int x,int y)
{mkrt(x); fa[x]=y;
}
void cut(int x,int y)
{mkrt(x); access(y); splay(y);c[y][0]=0; pshp(y); fa[x]=0;
}
bool chk(int x,int y)
{mkrt(x); access(y); splay(y);while(c[y][0])y=c[y][0];return x==y;
}
void ins(Node cr,int id)
{int x=cr.x,y=cr.y;if(chk(x,y)){splay(x);Dt tp=mn[x]; if(tp.t>cr.t)return;Node k=a[tp.id]; int bh=tp.bh;cut(k.x,bh); cut(k.y,bh); del_pl[++del_top]=bh;}int nw=New(); mn[nw]=vl[nw]=Dt(cr.t,id,nw);link(cr.x,nw); link(cr.y,nw);
}
int qry(int x,int y)
{if(!chk(x,y))return 0;splay(x); return mn[x].t;
}
int main()
{n=rdn();m=rdn();for(int i=1;i<=n;i++)mn[i]=vl[i]=Dt(0,0,0); tot=n;for(int i=1;i<=m;i++){op[i]=rdn();int x=rdn(),y=rdn();if(x>y)swap(x,y);//
      if(op[i]==0)mp[mkp(x,y)]=i,a[i].x=x,a[i].y=y,a[i].t=m+1;//m+1else if(op[i]==1)a[mp[mkp(x,y)]].t=i;else a[i].x=x,a[i].y=y;}for(int i=1;i<=m;i++){if(op[i]==0)ins(a[i],i);if(op[i]==2)puts(qry(a[i].x,a[i].y)>i?"Y":"N");}return 0;
}

View Code

或者可以线段树分治。

线段树分治就是离线,按操作时间建一个线段树,把修改放在树上,然后遍历线段树,支持修改的栈序撤销,走到叶子就可以知道那个时刻的答案。

这道题就是给线段树节点开 vector 存它有些什么边,然后并查集按秩合并,就可以栈序撤销了。

比 LCT 快了一倍。

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#include<map>
#define ls Ls[cr]
#define rs Rs[cr]
#define pb push_back
#define mkp make_pair
using namespace std;
int rdn()
{int ret=0;bool fx=1;char ch=getchar();while(ch>'9'||ch<'0'){if(ch=='-')fx=0;ch=getchar();}while(ch>='0'&&ch<='9')ret=ret*10+ch-'0',ch=getchar();return fx?ret:-ret;
}
const int N=5005,M=5e5+5,K=20;
int n,m,op[M],fa[N],siz[N],top; bool vis[M],ans[M];
int tot,Ls[M<<1],Rs[M<<1],sm[M<<1];
struct Node{int x,y;Node(int x=0,int y=0):x(x),y(y) {}
}a[M],sta[N];
vector<Node> vt[M<<1];
map<pair<int,int>,int> mp;
void build(int l,int r,int cr)
{if(l==r)return; int mid=l+r>>1;ls=++tot; build(l,mid,ls);rs=++tot; build(mid+1,r,rs);
}
void ins(int l,int r,int cr,int L,int R,Node k)
{if(l>=L&&r<=R){vt[cr].pb(k);return;}int mid=l+r>>1;if(L<=mid)ins(l,mid,ls,L,R,k);if(mid<R)ins(mid+1,r,rs,L,R,k);
}
void cz(int l,int r,int cr)
{if(l==r){sm[cr]=(op[l]==2?1:0);return;}int mid=l+r>>1;cz(l,mid,ls); cz(mid+1,r,rs);sm[cr]=sm[ls]+sm[rs];
}
int fnd(int a){return fa[a]==a?a:fnd(fa[a]);}
void mrg(Node a)
{int x=fnd(a.x),y=fnd(a.y);if(x==y)return; if(siz[x]<siz[y])swap(x,y);sta[++top]=Node(y,x); fa[y]=x; siz[x]+=siz[y];
}
void solve(int l,int r,int cr)
{int sz=vt[cr].size();for(int i=0;i<sz;i++)mrg(vt[cr][i]);if(l==r){ans[l]=(fnd(a[l].x)==fnd(a[l].y));return;}int mid=l+r>>1;if(sm[ls]){int nw=top; solve(l,mid,ls);for(int& i=top;i>nw;i--){int x=sta[i].x,y=sta[i].y;fa[x]=x; siz[y]-=siz[x];}}if(sm[rs]){int nw=top; solve(mid+1,r,rs);for(int& i=top;i>nw;i--){int x=sta[i].x,y=sta[i].y;fa[x]=x; siz[y]-=siz[x];}}
}
int main()
{n=rdn();m=rdn();tot=1;build(1,m,1);for(int i=1;i<=m;i++){op[i]=rdn();int x=rdn(),y=rdn();if(x>y)swap(x,y);//
      if(!op[i]){a[i]=Node(x,y);mp[mkp(x,y)]=i;}else if(op[i]==1){int bh=mp[mkp(x,y)]; vis[bh]=1;ins(1,m,1,bh,i-1,a[bh]);}else a[i]=Node(x,y);}for(int i=1;i<=m;i++)if(!op[i]&&!vis[i])ins(1,m,1,i,m,a[i]);cz(1,m,1); for(int i=1;i<=n;i++)fa[i]=i,siz[i]=1;solve(1,m,1);for(int i=1;i<=m;i++)if(op[i]==2)puts(ans[i]?"Y":"N");return 0;
}

View Code

转载于:https://www.cnblogs.com/Narh/p/10372004.html

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

  1. Loj #2324. 「清华集训 2017」小 Y 和二叉树

    Loj #2324. 「清华集训 2017」小 Y 和二叉树 小Y是一个心灵手巧的OIer,她有许多二叉树模型. 小Y的二叉树模型中,每个结点都具有一个编号,小Y把她最喜欢的一个二叉树模型挂在了墙上, ...

  2. [LOJ#522]「LibreOJ β Round #3」绯色 IOI(危机)

    [LOJ#522]「LibreOJ β Round #3」绯色 IOI(危机) 试题描述 IOI 的比赛开始了.Jsp 和 Rlc 坐在一个角落,这时他们听到了一个异样的声音 -- 接着他们发现自己收 ...

  3. [LOJ#2329]「清华集训 2017」我的生命已如风中残烛

    [LOJ#2329]「清华集训 2017」我的生命已如风中残烛 试题描述 九条可怜是一个贪玩的女孩子. 这天她在一堵墙钉了 \(n\) 个钉子,第 \(i\) 个钉子的坐标是 \((x_i,y_i)\ ...

  4. [线段树分治][DP] LOJ #534. 「LibreOJ Round #6」花团

    Solution S o l u t i o n Solution 操作相当于是动态的做一个背包DP. 离线的话,线段树分治一下. 因为结尾是已知的,可以一边分治,得到一个修改操作,就插到线段树. 只 ...

  5. LOJ 2312(洛谷 3733) 「HAOI2017」八纵八横——线段树分治+线性基+bitset

    题目:https://loj.ac/problem/2312 https://www.luogu.org/problemnew/show/P3733 原本以为要线段树分治+LCT,查了查发现环上的值直 ...

  6. 线段树分治 ---- CF1217F - Forced Online Queries Problem(假离线 可撤销并查集 + 线段树分治)详解

    题目链接 题目大意 解题思路: 我一开始想到可以用可撤销并查集去维护这种删边加边的操作,但是有个缺点是每次撤销都有把后面的边全部撤销复度是O(n2)O(n^2)O(n2) 首先我们考虑这种动态加边删边 ...

  7. 动态图连通性(线段树分治+按秩合并并查集)

    在考场上遇到了这个的板子题,,,所以来学习了一下线段树分治 + 带撤销的并查集. 题目大意是这样的:有m个时刻,每个时刻有一个加边or撤销一条边的操作,保证操作合法,没有重边自环,每次操作后输出当前图 ...

  8. 【题解】【LibreOJ Round #6】花团 LOJ 534 时间线段树分治 背包

    Prelude 题目链接:萌萌哒传送门(/≧▽≦)/ Solution 如果完全离线的话,可以直接用时间线段树分治来做,复杂度\(O(qv \log q)\). 现在在线了怎么办呢? 这其实是个假在线 ...

  9. #Loj121 动态图连通性

    Description 你要维护一张无向简单图.你被要求加入删除一条边及查询两个点是否连通. 0:加入一条边.保证它不存在. 1:删除一条边.保证它存在. 2:查询两个点是否联通. Input 输入的 ...

最新文章

  1. 学习笔记Flink(八)—— 基于Flink 在线交易反欺诈检测
  2. 6.Spring Cloud Alibaba教程:Sentinel流量防卫兵的介绍与基本使用
  3. tomcat JRE_HOME
  4. 清华放大招!竟然连初三学生都招,一条龙培养到博士,还不准转专业......
  5. 微软MS10-046漏洞的利用
  6. android 相册 标签,在Android标签上,如何在图片下方显示文字?
  7. 【你必须知道的.NET】:【大话String】
  8. 风控体系建设、数字化转型、金融科技应用前,您是如何看待数据问题的?
  9. matlab2014a VS2010混合编程
  10. win7 做无盘服务器配置,两种方法轻松实现无盘安装Win7系统
  11. 商业计划书-智能导盲仗
  12. 计算机电子电路原理图,经典六款电路图集锦(图文)
  13. 一、Netflix Eureka
  14. 几个在线的web代理
  15. TQFP 和LQFP 器件的焊接方法
  16. EOS区块链一周要闻回顾(2.24-3.01)
  17. Win10+yolov5 踩坑记录
  18. 澳洲八大的IB(International Baccalaureate)成绩录取要求
  19. 穷爸爸,富爸爸学习笔记
  20. 苹果浏览器显示打不开改网页无法连接服务器,为什么苹果浏览器老是显示safari打不开该网页答案...

热门文章

  1. boost::hana::intersection用法的测试程序
  2. boost::container模块实现虚拟测试分配器的程序
  3. ITK:计算Sigmoid
  4. DCMTK:测试DcmSCPPool类,包括DcmSCP和DcmSCU交互
  5. OpenCV拼接细节stitching detailed的实例(附完整代码)
  6. 在Qt Designer中使用样式表
  7. Qt Creator添加Qt Designer插件
  8. C语言求两个链表的合并点的算法(附完整源码)
  9. OpenGL相机控制之一
  10. C++何时调用拷贝(复制)构造函数