#3145. 「APIO 2019」桥梁
#3145. 「APIO 2019」桥梁
题目描述
圣彼得堡市内所有水路长度总和约 282 千米,市内水域面积占城市面积的 7%。——来自维基百科
圣彼得堡位于由 \(m\) 座桥梁连接而成的 \(n\) 个岛屿上。岛屿用 \(1\) 到 \(n\) 的整数编号,桥梁用 \(1\) 到 \(m\) 的整数编号。每座桥连接两个不同的岛屿。有些桥梁是在彼得大帝时代建造的,其中一些是近期建造的。这导致了不同的桥梁可能有不同的重量限制。更具体地,只有重量不超过 \(d_i\) 的汽车才能通过第 \(i\) 座桥梁。有时圣彼得堡的一些桥梁会进行翻新,但这并不一定会使桥梁承重变得更好,也就是说,进行翻新的桥梁的 \(d_i\) 可能会增加或减少。你准备开发一个产品,用于帮助公民和城市客人。目前,你开发的模块要能执行两种类型的操作:
\1. 将桥梁 \(b_j\) 的重量限制改为 \(r_j\)。
\2. 统计一辆重为 \(w_j\) 的汽车从岛屿 \(s_j\) 出发能够到达多少个不同的岛屿。
请你回答所有第二种操作的答案。
输入格式
第一行包含两个整数 \(n\) 和 \(m\)——表示圣彼得堡的岛屿数量与桥梁数量。
接下来 \(m\) 行,每行三个整数 \(u_i, v_i, d_i\)。第 \(i\) 行的整数描述了一座连接岛屿 \(u_i\) 和 \(v_i\),初始时重量限制为 \(d_i\) 的桥梁。
接下来一行一个整数 \(q\)——表示操作的数量。
接下来 \(q\) 行按顺序每行描述一个操作。
每行第一个整数 \(t_j\) 表示操作类型:
- 若 \(t_j = 1\),则该操作是第一种类型,该行接下来给定两个整数 \(b_j\) 和 \(r_j\),表示桥梁 \(b_j\) 的重量限制将变为 \(r_j\)。
- 若 \(t_j = 2\),则该操作是第二种类型,该行接下来给定两个整数 \(s_j\) 和 \(w_j\),表示一辆重为 \(w_j\) 的汽车将要从第 \(s_j\) 个岛屿出发。
输出格式
对于每个第二种类型的询问,输出一行一个整数表示答案。
数据范围与提示
对于全部数据,\(1\le n\le 5\times 10^4,0\le m\le 10^5,1\le q\le 10^5\)。保证 \(1\le u_i,v_i,s_j\le n,u_i\not =v_i,1\le d_i,r_j,w_j\le 10^9,1\le b_j\le m,t_j\in\{1,2\}\)。
我们把一次修改视作产生了两条不同的边,每条边都有一个存在的时间。
将操作序列分块,对每个块内的询问分别处理。将询问的\(w\)升序排列,将出现在这个块之前,并且在这个块之后再消失的边按\(w\)排序。依次处理询问时,依次加入这些边,用路径压缩的并查集。每一次询问时,对于结束时间在这个块内的边,我们暴力判断是否要加入,询问了之后再撤销。这部分用按秩合并的并查集。
复杂度\(O(m\sqrt{mlog(n)})\)
代码:
#include<bits/stdc++.h>
#define ll long long
#define N 100005
using namespace std;
inline int Get() {int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9') {if(ch=='-') f=-1;ch=getchar();}while('0'<=ch&&ch<='9') {x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}return x*f;}
int n,m,q;
const int blk=600;
int bel[N];
struct edge {
int x,y,w;
int l,r;
bool operator <(const edge &a)const {return w>a.w;}
}e[N<<1];
bool cmpe(int a,int b) {
return e[a].w>e[b].w;
}
int etot;
int lst[N];
int op[N];
int E[N],pos[N],w[N];
vector<int>que[N/blk+5];
bool cmp(int a,int b) {return w[a]>w[b];}
int fa[N],size[N],dep[N];
int Getf(int v) {return v==fa[v]?v:fa[v]=Getf(fa[v]);}
int Getf2(int v) {
while(v!=fa[v]) v=fa[v];
return v;
}
void Merge(int a,int b) {
a=Getf(a),b=Getf(b);
if(a==b) return ;
fa[a]=b;
size[b]+=size[a];
}
void Init() {for(int i=1;i<=n;i++) fa[i]=i,size[i]=1,dep[i]=1;}
vector<int>tem;
int L[N],R[N];
struct node {
int x,size,dep;
node() {}
node(int _x,int _size,int _dep) {x=_x,size=_size,dep=_dep;}
};
vector<node>undo;
vector<int>st,st2;
int ans[N];
void Merge(vector<int>&a,vector<int>&b) {
static vector<int>st;
st.clear();
int ta=0,tb=0;
while(ta!=a.size()||tb!=b.size()) {
if(ta==a.size()) st.push_back(b[tb]),tb++;
else if(tb==b.size()) st.push_back(a[ta]),ta++;
else if(e[a[ta]].w>e[b[tb]].w) st.push_back(a[ta]),ta++;
else st.push_back(b[tb]),tb++;
}
a.clear();
for(int i=0;i<st.size();i++) a.push_back(st[i]);
}
int main() {
n=Get(),m=Get();
for(int i=1;i<=m;i++) {
e[i].x=Get(),e[i].y=Get(),e[i].w=Get();
}
q=Get();
for(int i=1;i<=m;i++) {
lst[i]=i;
e[i].l=1,e[i].r=q;
}
etot=m;
int x,y;
for(int i=1;i<=q;i++) {
op[i]=Get();
x=Get(),y=Get();
if(op[i]==1) {
E[i]=++etot;
e[E[i]]=e[lst[x]];
e[E[i]].w=y;
e[lst[x]].r=i-1;
e[E[i]].l=i;
e[E[i]].r=q;
lst[x]=etot;
} else {
pos[i]=x,w[i]=y;
}
}
sort(e+1,e+1+m);
for(int i=1;i<=m;i++) if(e[i].r) st.push_back(i);
for(int i=1;i<=q;i++) bel[i]=(i-1)/blk+1;
for(int i=1;i<=bel[q];i++) L[i]=(i-1)*blk+1,R[i]=min(q,i*blk);
for(int i=1;i<=q;i++) if(op[i]==2) que[bel[i]].push_back(i);
for(int i=1;i<=bel[q];i++) {
sort(que[i].begin(),que[i].end(),cmp);
Init();
tem.clear();
for(int j=L[i];j<=R[i];j++) if(op[j]==1) tem.push_back(E[j]);
int tag=0;
for(int j=0;j<que[i].size();j++) {
int now=que[i][j];
while(tag<st.size()&&e[st[tag]].w>=w[now]) {
if(e[st[tag]].r>=R[i]) {
Merge(e[st[tag]].x,e[st[tag]].y);
} else if(e[st[tag]].r>=L[i]) tem.push_back(st[tag]);
tag++;
}
for(int k=0;k<tem.size();k++) {
int x=e[tem[k]].x,y=e[tem[k]].y;
Getf(x),Getf(y);
}
undo.clear();
for(int k=0;k<tem.size();k++) {
int id=tem[k];
if(e[id].l<=now&&now<=e[id].r&&e[id].w>=w[now]) {
int x=Getf2(e[id].x),y=Getf2(e[id].y);
if(x==y) continue ;
undo.push_back(node(x,size[x],dep[x]));
undo.push_back(node(y,size[y],dep[y]));
if(dep[x]>dep[y]) swap(x,y);
fa[x]=y;
size[y]+=size[x];
if(dep[x]==dep[y]) dep[y]++;
}
}
ans[now]=size[Getf2(pos[now])];
while(undo.size()) {
node a=undo.back();
undo.pop_back();
fa[a.x]=a.x;
size[a.x]=a.size;
dep[a.x]=a.dep;
}
}
st2.clear();
for(int j=L[i];j<=R[i];j++) if(op[j]==1) st2.push_back(E[j]);
sort(st2.begin(),st2.end(),cmpe);
Merge(st,st2);
}
for(int i=1;i<=q;i++) if(ans[i]) {
cout<<ans[i]<<"\n";
}
return 0;
}
#3145. 「APIO 2019」桥梁的更多相关文章
- 「APIO 2019」桥梁
题目 三天终于把\(APIO\)做完了 这题还是比较厉害的,如果不知道这是个分块应该就自闭了 考虑一个非常妙的操作,按照操作分块 我们设一个闸值\(S\),把\(S\)个边权修改操作分成一块,把所有的 ...
- #3146. 「APIO 2019」路灯
#3146. 「APIO 2019」路灯 题目描述 一辆自动驾驶的出租车正在 Innopolis 的街道上行驶.该街道上有 \(n + 1\) 个停车站点,它们将街道划分成了 \(n\) 条路段.每一 ...
- #3144. 「APIO 2019」奇怪装置
#3144. 「APIO 2019」奇怪装置 题目描述 考古学家发现古代文明留下了一种奇怪的装置.该装置包含两个屏幕,分别显示两个整数 \(x\) 和 \(y\). 经过研究,科学家对该装置得出了一个 ...
- 【LOJ #3144】「APIO 2019」奇怪装置
题意: 定义将一个\(t\)如下转换成一个二元组: \[ f(t) = \begin{cases} x = (t + \left\lfloor \frac{t}{B} \right \rfloor) ...
- 「APIO 2019」路灯
题目 显然一个熟练的选手应该能一眼看出我们需要维护点对的答案 显然在断开或连上某一条边的时候只会对左右两边联通的点产生贡献,这个拿\(set\)维护一下就好了 那现在的问题就是怎么维护了 考虑一个非常 ...
- 「APIO 2019」奇怪装置
题目 考虑推柿子 最开始的想法是如果两个\(t\)在\(mod\ B\)意义下相等,那么只需要比较一下\((t+\left \lfloor \frac{t}{B}\rfloor \right)mod\ ...
- 「WC 2019」数树
「WC 2019」数树 一道涨姿势的EGF好题,官方题解我并没有完全看懂,尝试用指数型生成函数和组合意义的角度推了一波.考场上只得了 44 分也暴露了我在数数的一些基本套路上的不足,后面的 \(\ex ...
- LOJ#3054. 「HNOI 2019」鱼
LOJ#3054. 「HNOI 2019」鱼 https://loj.ac/problem/3054 题意 平面上有n个点,问能组成几个六个点的鱼.(n<=1000) 分析 鱼题,劲啊. 容易想 ...
- 【题解】#6622. 「THUPC 2019」找树 / findtree(Matrix Tree+FWT)
[题解]#6622. 「THUPC 2019」找树 / findtree(Matrix Tree+FWT) 之前做这道题不理解,有一点走火入魔了,甚至想要一本近世代数来看,然后通过人类智慧思考后发现, ...
随机推荐
- LeetCode刷题191127
数据库: 1179 部门表 Department: +---------------+---------+| Column Name | Type |+---------------+-------- ...
- Python装饰器(Decorators )
http://book.pythontips.com/en/latest/decorators.html 在<Built-in Functions(3.6)>和<Python上下文管 ...
- 加权无向图 最小生成树 Prim算法 延迟版和即时版 村里修路该先修哪
本次要解决的问题是:你们村里那些坑坑洼洼的路,到底哪些路才是主干道? 小明:肯定是哪里都能到得了,并且去哪里都相对比较近,并且被大家共用程度高的路是啊! 具体是哪几条路呢?今天就可以给出准确答案 最小 ...
- typescript与nodejs(一)最简单的webserver
安装nodejs tsc cnpm vscode 这些略 如果网络慢,可以考虑使用CNPM 一. 基本WebServer模块环境 1. 命令行 npm init 初始化一个目录为nodejs项目 2 ...
- ubuntu16搭建文件服务器
这篇记录,如何在ubuntu16 安装 FastDFS 文件服务器,详细步骤 环境依赖 apt-get install make apt-get install unzip apt-get insta ...
- Kubernetes的Job对象
Deployment.StatefulSet及DaemonSet三个主要用来进行长时间业务,不会退出. 而有一些离线业务,或者叫Batch Job(计算业务),计算完成后就直接退出 了,如果用Depl ...
- SpringBoot配置文件yml ScannerException: while scanning an alias *
在使用yml编写配置我呢见 management: endpoints: web: base-path: /actuator jmx: exposure: include: * 报了如下错误 解决方案 ...
- Actor模型(分布式编程)
Actor的目的是为了解决分布式编程中的一系列问题.所有消息都是异步交付的,因此将消息发送方与接收方分开,正是由于这种分离,导致actor系统具有内在的并发性:可以不受限制地并行执行任何拥有输入消息的 ...
- (转)格拉布斯准则(Grubbs Criterion)处理数据异常
格拉布斯准则:https://baike.baidu.com/item/%E6%A0%BC%E6%8B%89%E5%B8%83%E6%96%AF%E5%87%86%E5%88%99/3909586 G ...
- Bootstrap 基于Bootstrap和JQuery实现动态打开和关闭tab页
基于Bootstrap和JQuery实现动态打开和关闭tab页 by:授客 QQ:1033553122 1. 测试环境 JQuery-3.2.1.min.j Bootstrap-3.3.7-d ...