#分块,可撤销并查集#洛谷 5443 [APIO2019]桥梁
分析
最直接的做法就是在线一边修改边权,询问直接全部重排,
然后用可撤销并查集维护连通块大小,这样时间复杂度为 \(O(qm)\)
同样尽量让大部分的边不需要修改边权,那么每 \(B\) 个操作整体进行一次,
那么最多只有 \(B\) 条边会修改,剩下的边直接用双指针加入并查集。
这 \(B\) 条边直接每次询问修改边权,然后排序加入并查集,询问完与剩下的边归并排序
那么时间复杂度为 \(O(qB\log n+\frac{m^2}{B}\log n)\),实际上 \(B\) 取 \(\sqrt{m\log n}\) 跑得比较快。
注意可撤销并查集不能通过siz的大小合并,只是为了方便,但可能会被卡。
代码
#include <cstdio>
#include <cctype>
#include <algorithm>
#include <cmath>
using namespace std;
const int N=100011; struct node{int x,y,w;}e[N]; struct rec{int x,y,rk;}q[N],a[N];
int n,m,Q,bl,f[N],rk[N],siz[N],ans[N],Fa[N],tod,Fb[N],v[N],Rk[N],RK[N],rK[N];
int iut(){
int ans=0; char c=getchar();
while (!isdigit(c)) c=getchar();
while (isdigit(c)) ans=ans*10+c-48,c=getchar();
return ans;
}
void print(int ans){
if (ans>9) print(ans/10);
putchar(ans%10+48);
}
bool cmp0(int x,int y){return e[x].w>e[y].w;}
bool cmp1(int x,int y){return q[x].y>q[y].y;}
int getf(int u){return f[u]==u?u:getf(f[u]);}
void Merge(int x,int y){
int fa=getf(x),fb=getf(y);
if (siz[fa]>siz[fb]) swap(fa,fb);
if (fa==fb) return;
f[fa]=fb,siz[fb]+=siz[fa],Fa[++tod]=fa,Fb[tod]=fb;
}
int main(){
n=iut(),m=iut();
for (int i=1;i<=m;++i) e[i]=(node){iut(),iut(),iut()};
for (int i=1;i<=n;++i) f[i]=i,siz[i]=1;
for (int i=1;i<=m;++i) rk[i]=i;
Q=iut(),bl=sqrt(m*log(n)),sort(rk+1,rk+1+m,cmp0);
for (int l=1,r;l<=Q;l+=bl){
if (l+bl>Q) r=Q; else r=l+bl-1;
int tot=0,cnt=0,TOT=0,ToT=0;
for (int i=l;i<=r;++i){
int opt=iut(),x=iut(),y=iut();
if (opt==1) ++tot,a[tot]=(rec){x,y,tot},v[x]=l;
else q[++cnt]=(rec){x,y,tot},Rk[cnt]=cnt;
}
if (!cnt) continue;
for (int i=1;i<=m;++i) if (v[i]==l) rK[++TOT]=i;
sort(Rk+1,Rk+1+cnt,cmp1);
for (int i=1,j=1;i<=cnt;++i){
for (;j<=m&&e[rk[j]].w>=q[Rk[i]].y;++j)
if (v[rk[j]]!=l) Merge(e[rk[j]].x,e[rk[j]].y);
for (int k=1;k<=q[Rk[i]].rk;++k) swap(e[a[k].x].w,a[k].y);
int Tod=tod;
for (int k=1;k<=TOT;++k)
if (e[rK[k]].w>=q[Rk[i]].y)
Merge(e[rK[k]].x,e[rK[k]].y);
ans[Rk[i]]=siz[getf(q[Rk[i]].x)];
for (;tod>Tod;--tod) siz[Fb[tod]]-=siz[Fa[tod]],f[Fa[tod]]=Fa[tod];
for (int k=q[Rk[i]].rk;k;--k) swap(e[a[k].x].w,a[k].y);
}
for (;tod;--tod) siz[Fb[tod]]-=siz[Fa[tod]],f[Fa[tod]]=Fa[tod];
for (int k=1;k<=tot;++k) swap(e[a[k].x].w,a[k].y);
sort(rK+1,rK+1+TOT,cmp0);
int I=1,J=1;
while (I<=TOT){
while (J<=m&&v[rk[J]]==l) ++J;
if (J<=m&&e[rk[J]].w>=e[rK[I]].w) RK[++ToT]=rk[J++];
else RK[++ToT]=rK[I++];
}
for (;J<=m;++J) if (v[rk[J]]!=l) RK[++ToT]=rk[J];
for (int i=1;i<=ToT;++i) rk[i]=RK[i];
for (int i=1;i<=cnt;++i) print(ans[i]),putchar(10);
}
return 0;
}
#分块,可撤销并查集#洛谷 5443 [APIO2019]桥梁的更多相关文章
- [BZOJ4537][Hnoi2016]最小公倍数 奇怪的分块+可撤销并查集
4537: [Hnoi2016]最小公倍数 Time Limit: 40 Sec Memory Limit: 512 MBSubmit: 1474 Solved: 521[Submit][Stat ...
- 【简单数据结构】并查集--洛谷 P1111
题目背景 AA地区在地震过后,连接所有村庄的公路都造成了损坏而无法通车.政府派人修复这些公路. 题目描述 给出A地区的村庄数NN,和公路数MM,公路是双向的.并告诉你每条公路的连着哪两个村庄,并告诉你 ...
- bzoj2049 线段树 + 可撤销并查集
https://www.lydsy.com/JudgeOnline/problem.php?id=2049 线段树真神奇 题意:给出一波操作,拆边加边以及询问两点是否联通. 听说常规方法是在线LCT, ...
- CodeForces892E 可撤销并查集/最小生成树
http://codeforces.com/problemset/problem/892/E 题意:给出一个 n 个点 m 条边的无向图,每条边有边权,共 Q 次询问,每次给出 ki 条边,问这些边 ...
- BZOJ4358: permu(带撤销并查集 不删除莫队)
题意 题目链接 Sol 感觉自己已经老的爬不动了.. 想了一会儿,大概用个不删除莫队+带撤销并查集就能搞了吧,\(n \sqrt{n} logn\)应该卡的过去 不过不删除莫队咋写来着?....跑去学 ...
- 【离线 撤销并查集 线段树分治】bzoj1018: [SHOI2008]堵塞的交通traffic
本题可化成更一般的问题:离线动态图询问连通性 当然可以利用它的特殊性质,采用在线线段树维护一些标记的方法 Description 有一天,由于某种穿越现象作用,你来到了传说中的小人国.小人国的布局非常 ...
- codeforces 892E(离散化+可撤销并查集)
题意 给出一个n个点m条边的无向联通图(n,m<=5e5),有q(q<=5e5)个询问 每个询问询问一个边集{Ei},回答这些边能否在同一个最小生成树中 分析 要知道一个性质,就是权值不同 ...
- 【Codeforces576E_CF576E】Painting Edges(可撤销并查集+线段树分治)
题目 CF576E 分析: 从前天早上肝到明天早上qwq其实颓了一上午MC ,自己瞎yy然后1A,写篇博客庆祝一下. 首先做这题之前推荐一道很相似的题:[BZOJ4025]二分图(可撤销并查集+线段树 ...
- 【BZOJ4025】二分图(可撤销并查集+线段树分治)
题目: BZOJ4025 分析: 定理:一个图是二分图的充要条件是不存在奇环. 先考虑一个弱化的问题:保证所有边出现的时间段不会交叉,只会包含或相离. 还是不会?再考虑一个更弱化的问题:边只会出现不会 ...
- 算法笔记--可撤销并查集 && 可持久化并查集
可撤销并查集模板: struct UFS { stack<pair<int*, int>> stk; int fa[N], rnk[N]; inline void init(i ...
随机推荐
- 进程之间共享数据Manager,线程相关使用Thread,用类定义线程,守护线程setDaemon,线程锁Lock,线程信号量Semaphore---day32
1.Manager # ### Manager (list列表,dict字典)进程之间的共享数据(列表或字典等) from multiprocessing import Process,Manager ...
- 用Visual Studio把代码放到GitLab
1.点"Git更改" 2.点"创建Git仓库--": 3.点"现有远程",再输入"远程URL": 4.在出现的警告框里选 ...
- JAVA对象生命周期(三)-对象的销毁
目录 从引用说起 指针直接引用 句柄引用 优缺点 如何判断对象死亡 引用计数法 可达性分析法 垃圾收集算法 标记-清除算法 复制算法 复制算法--优化 有关年轻代的JVM参数 标记-整理算法 分代收集 ...
- Java 数组查找
1 //要找的数 - 数组中的第一个元素 / 最大的数 - 第一个元素 2 //数组的查找(线性查找 二分法查找) 3 //线性查找: 4 //equals 5 6 String dest = &qu ...
- XSS漏洞原理整理
一.通常使用XSS脚本来获取浏览器版本信息,alert(navigator.userAgnet ) ,浏览器的UserAgent是可以伪造的,比方火狐或者很多扩展都可以屏蔽或者自定义浏览器发送的Us ...
- Mysql使用limit深度分页优化
1.背景: mysql使用select * limit offset, rows分页在深度分页的情况下.性能急剧下降. 例如:select * 的情况下直接⽤limit 600000,10 扫描的是约 ...
- 从零开始学Spring Boot系列-集成mybatis
在Spring Boot的应用开发中,MyBatis是一个非常流行的持久层框架,它支持定制化SQL.存储过程以及高级映射.在本篇文章中,我们将学习如何在Spring Boot项目中集成MyBatis, ...
- C++学习笔记之高级语法
目录 高级语法 面向对象--类 对象的属性 运算符重载 拷贝构造函数 IO缓存 头文件的重复包含问题 深拷贝与浅拷贝 面向对象三大特性 高级语法 面向对象--类 C++使用struct.class来定 ...
- Kinaba discover查询语法
1.要搜索一个确切的字符串,即精确搜索,需要使用双引号引起来:path:"/app/logs/nginx/access.log" 2.如果不带引号,将会匹配每个单词:uid tok ...
- Android Material组件库(日期选择和时间选择器)基本使用
原文:Android Material组件库(日期选择和时间选择器)基本使用 - Stars-One的杂货小窝 简单的封装下Material组件里的日期选择器和时间选择器的使用方法 效果 代码 需要添 ...