problem

\(\mathrm {loj-3145}\)

题意概要:给定一张 \(n\) 点 \(m\) 边的无向图,边有边权,共 \(q\) 次操作,每次会将第 \(x\) 条边的权值改为 \(y\),或询问从 \(x\) 开始只走大于等于 \(y\) 的边能到达多少点。

\(n\leq 5\times 10^4,\ m,q\leq 10^5\)

Solution

这道题和 \(HNOI2016\) 最小公因数 长得很像,想到分块就会了。由于这题有修改,对询问的权值分块不好做,就只能对操作分块了。

设操作块大小为 \(T\),则共 \(\lceil\frac qT \rceil\) 个操作快。

对于每一个操作块,按照询问的权值大小顺序询问(否则就需要上可持久化并查集)。需要考虑两者的贡献:在块内被修改了的边、在块内未被修改的边。后者可以依照询问的权值大小依次添加,而由于目前将询问按权值大小排序,所以询问时间不一定递增,可以暴力处理块内修改,查看这条边是否有用。

对于每一个询问,需要暴力扫描块内的修改,每次修改因为需要支持并查集撤销,复杂度 \(O(T\log n)\)。总共 \(q\) 个询问,共 \(O(qT\log n)\)。

对于每一块而言,需要将所有边排序、块内询问排序,处理整块排序时会重构整个并查集,复杂度 \(O(n+m\log m+T\log T)\),由于 \(n,m,q\) 同阶,所以简化为 \(O(m\log m)\)。总共 \(\lceil \frac qT\rceil\) 块,共 \(O(\frac qT\cdot m\log m)\)。

考虑到 \(n,m,q\) 同阶,总复杂度为 \(O(mT\log m+\frac {m^2\log m}T)=O(m\log m(T+\frac mT))\),取 \(T=m^{\frac 12}\) 得复杂度最低为 \(O(m^{\frac 32}\log m)\)。到这就能过了

实际上没必要每一块内重新排序,可以将一开始排序后的序列拆出来,复杂度 \(O(m)\),重新计算复杂度得 \(O(mT\log m+\frac {m^2}T)\),取 \(T=\sqrt {m\log m}\) 可得 \(O(m^{\frac 32}\sqrt {\log m})\)……但效率差别并不是很大。

Code

这里写的是前一个版本的。

//loj-3145
#include <bits/stdc++.h>
using namespace std; template <typename _tp> inline void read(_tp&x){
char ch=getchar(),ob=0;x=0;
while(ch!='-'&&!isdigit(ch))ch=getchar();if(ch=='-')ob=1,ch=getchar();
while(isdigit(ch))x=x*10+ch-'0',ch=getchar();if(ob)x=-x;
} const int N = 101000;
int n, m, Q; struct Edge {
int l, r, w, id;
inline void in() {read(l), read(r), read(w);}
friend inline bool operator < (const Edge&A, const Edge&B) {return A.w > B.w;}
}e[N], ee[N]; struct Qry {
int op, x, y, id;
inline void in() {read(op), read(x), read(y);}
friend inline bool operator < (const Qry&A, const Qry&B) {return A.y > B.y;}
}q[N], md[N], qr[N]; int d[N], sz[N];
inline int f(int x) {while(d[x]) x = d[x]; return x;} struct RUB {int x, dx, y, sy;}Rub[N];
int rub; inline void merge(int x, int y) {
x = f(x), y = f(y); if(x == y) return ;
if(sz[x] > sz[y]) swap(x, y);
Rub[++rub] = (RUB) {x, d[x], y, sz[y]};
d[x] = y, sz[y] += sz[x];
} inline void cancel() {while(rub) d[Rub[rub].x] = Rub[rub].dx, sz[Rub[rub].y] = Rub[rub].sy, --rub;} int Ans[N], st[N], ew[N];
bool ex[N]; int main() {
read(n), read(m);
for(int i=1;i<=m;++i) e[i].in(), e[i].id = i;
int T = max(1.0, sqrt(m*log(m)/log(2)));
read(Q);
for(int l=1,r=T;l<=Q;l+=T) {
r = min(Q, l+T-1);
int t = r - l + 1, t0 = 0, t1 = 0; for(int i=1;i<=m;++i) ex[i] = false; for(int i=1;i<=t;++i) {
Ans[i] = 0, q[i].in(), q[i].id = i;
if(q[i].op == 1) md[++t0] = q[i], ex[q[i].x] = true;
else qr[++t1] = q[i];
}
sort(qr+1, qr+t1+1); for(int i=1;i<=n;++i) d[i] = 0, sz[i] = 1; int em = 0, tp = 0;
for(int i=1;i<=m;++i)
if(!ex[i]) ee[++em] = e[i];
else st[++tp] = i;
sort(ee+1, ee+em+1); int ie = 1;
for(int i=1;i<=t1;++i) {
while(ie <= em and ee[ie].w >= qr[i].y)
merge(ee[ie].l, ee[ie].r), ++ie; for(int j=1;j<=tp;++j) ew[st[j]] = e[st[j]].w;
for(int j=1;j<=t0 and md[j].id <= qr[i].id;++j)
ew[md[j].x] = md[j].y;
rub = 0;
for(int j=1;j<=tp;++j)
if(ew[st[j]] >= qr[i].y)
merge(e[st[j]].l, e[st[j]].r);
Ans[qr[i].id] = sz[f(qr[i].x)];
cancel();
}
for(int i=1;i<=t0;++i)
e[md[i].x].w = md[i].y;
for(int i=1;i<=t;++i)
if(Ans[i]) printf("%d\n", Ans[i]);
}
return 0;
}

题解-APIO2019桥梁的更多相关文章

  1. 【LOJ#3145】[APIO2019]桥梁(分块,并查集)

    [LOJ#3145][APIO2019]桥梁(分块,并查集) 题面 LOJ 题解 因为某个\(\text{subtask}\)没判\(n=1\)的情况导致我自闭了很久的题目... 如果没有修改操作,可 ...

  2. 题解 洛谷 P5443 【[APIO2019]桥梁】

    考虑若只有查询操作,那么就可以构造\(Kruskal\)重构树,然后在线询问了,也可以更简单的把询问离线,把询问和边都按权值从大到小排序,然后双指针依次加入对于当前询问合法的边,用并查集维护每个点的答 ...

  3. 题解-APIO2019路灯

    problem \(\mathtt {loj-3146}\) 题意概要:一条直线上有 \(n+1\) 个点和 \(n\) 条道路,每条道路连通相邻两个点.在 \(q\) 个时刻内,每个时刻有如下两种操 ...

  4. 题解-APIO2019奇怪装置

    problem loj-3144 题意概要:设函数 \(f(t)\) 的返回值为一个二元组,即 \(f(t)=((t+\lfloor \frac tB\rfloor)\bmod A, t\bmod B ...

  5. P5443 [APIO2019]桥梁

    传送门 子任务 $4$ 告诉我们可以离线搞带权并查集 从大到小枚举询问,从大到小连边 如果没有修改操作就可以过了 但是有修改,考虑最暴力的暴力,搞可撤销并查集 同样先离线,从大到小处理询问时,按原边权 ...

  6. P5443 [APIO2019]桥梁 [分块+并查集]

    分块+并查集,大板子,没了. 并查集不路径压缩,可撤销,然后暴力删除 这样对于每个块都是独立的,所以直接搞就行了. 然后块内修改操作搞掉,就是单独的了 // powered by c++11 // b ...

  7. APIO2019简要题解

    Luogu P5444 [APIO2019]奇怪装置 看到这种题,我们肯定会想到\((x,y)\)一定有循环 我们要找到循环节的长度 推一下发现\(x\)的循环节长为\(\frac{AB}{B+1}\ ...

  8. 【APIO2019】桥梁(询问分块)

    Description 给定一张 \(n\) 个点,\(m\) 条边的无向图,边 \(i\) 的权值为 \(d_i\).现有 \(q\) 次操作,第 \(j\) 个操作有两种模式: \(1\ b_j\ ...

  9. APIO2019 题解

    APIO2019 题解 T1 奇怪装置 题目传送门 https://loj.ac/problem/3144 题解 很容易发现,这个东西一定会形成一个环.我们只需要求出环的长度就解决了一切问题. 设环的 ...

随机推荐

  1. 肠道微生物研究进展 | Microbiology | Human Gut Microbiome | human gut microbiota

    之前我有过一篇16s基本概念和数据分析的文章.16S 基础知识.分析工具和分析流程详解 可以分成两部分,生物层面和技术层面. 生物层面: 1. 肠道微生物里面包含了哪些微生物?显然包含了所有层面的微生 ...

  2. 即时通信系统IM--XMPP

    即时通讯(Instant Messaging)是目前Internet上最为流行的通讯方式,各种各样的即时通讯软件也层出不穷:服务提供商也提供了越来越丰富的通讯服务功能. 不容置疑,Internet已经 ...

  3. 数据库中的union与union all的区别

    Union因为要进行重复值扫描,所以效率低.如果合并没有刻意要删除重复行,那么就使用Union All  两个要联合的SQL语句 字段个数必须一样,而且字段类型要“相容”(一致): 如果我们需要将两个 ...

  4. 如何使用eclipse创建简单的servlet

    Servlet是一种基于java开发的服务器程序,可以对外公布服务,如果是浏览器应用,可以通过浏览器打开网址的方式查看服务.创建servlet要继承httpservlet,并且在web.xml中配置拦 ...

  5. MySQL 正则(Regular Expression) 邮箱(Email)

    MySQL 正则表达式 | 菜鸟教程https://www.runoob.com/mysql/mysql-regexp.html (1条消息)常用正则表达式—邮箱(Email) - Samuel - ...

  6. Remix 搭建与简单使用,并支持外部访问

    Remix 搭建与简单使用,并支持外部访问 转 https://blog.csdn.net/linshenyuan1213/article/details/83444911 remix是基于浏览器的在 ...

  7. git merge 结果是 git merge Already up-to-date. 该怎么解决?

    git将主干合并到当前分支时,出现如下结果: 原因在于:执行git merge前,主干的代码没有更新 正确的操作步骤如下: 1 .切换到主干 $ git checkout master 2. 更新主干 ...

  8. oracle存储过程中%type的含义

    转: oracle存储过程中%type的含义 2018-11-07 11:43:56 lizhi_ma 阅读数 1361更多 分类专栏: 数据库   版权声明:本文为博主原创文章,遵循CC 4.0 B ...

  9. svn使用步骤

    这里只是记录大概使用过程,操作步骤只供参考,不要按部就班. 1.安装SVN 服务端Setup-Subversion-1.6.5.msi和客户端TortoiseSVN-1.6.5.16974-win32 ...

  10. iOS 给view,button,text filed,label等添加边框和颜色

    self.tfaaa.layer.borderWidth = 2; self.tfaaa.layer.borderColor = [UIColor blueColor].CGColor;