#分治,Kruskal#洛谷 3206 [HNOI2010]城市建设
题目
动态改边权求最小生成树
\(n\leq 2*10^4,m\leq 5*10^4,q\leq 5*10^4\)
分析
乍一看是线段树分治,但有一个很大的问题就是局部的Kruskal不一定是最后的选择,
但是如果在底部再处理所有边的话,那仍然是 \(O(qm\log m)\) 的复杂度,必须在到达底层之前处理掉一些边。
由于所有边只是边权改变,并不需要线段树分治(常数会更大)。
分治到 \([l,r]\) 区间时,考虑两种特殊情况,就是需要修改的边无限大或者无限小。
无限小的时候,如果其它边被选上了,那么它们在之后肯定也会被选上,
直接缩成同一个连通块并统计答案,这样就保证点数一定与 \(r-l\) 同级
无限大的时候,如果没有被选上,一定不会被选上,直接不管这些边,
这样在无限小之后保证边数与点数同级。
各跑一次Kruskal,时间复杂度 \(O(m\log q\log m)\)
代码
#include <cstdio>
#include <cctype>
#include <algorithm>
using namespace std;
const int N=50011,inf=1e9; typedef long long lll;
struct rec{int x,w;}q[N];
struct node{int x,y,w,rk;}e[21][N],E[N];
int edge[21],w[N],rk[N],f[N],b[N],n,m,Q; lll ans[21];
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(lll ans){
if (ans>9) print(ans/10);
putchar(ans%10+48);
}
bool cmp(node x,node y){return x.w<y.w;}
int getf(int u){return f[u]==u?u:f[u]=getf(f[u]);}
void dfs(int dep,int l,int r){
int Edge=edge[dep]; lll Ans=ans[dep];
if (l==r) w[q[l].x]=q[l].w;
for (int i=1;i<=Edge;++i){
e[dep][i].w=w[e[dep][i].rk];
E[i]=e[dep][i],rk[E[i].rk]=i;
}
if (l==r){
sort(E+1,E+1+Edge,cmp);
for (int i=1;i<=Edge;++i)
f[E[i].x]=E[i].x,f[E[i].y]=E[i].y;
for (int i=1;i<=Edge;++i){
int fa=getf(E[i].x),fb=getf(E[i].y);
if (fa>fb) fa^=fb,fb^=fa,fa^=fb;
if (fa!=fb) Ans+=E[i].w,f[fa]=fb;
}
print(Ans),putchar(10);
return;
}
for (int i=l;i<=r;++i) E[rk[q[i].x]].w=-inf;
for (int i=1;i<=Edge;++i) f[E[i].x]=E[i].x,f[E[i].y]=E[i].y;
sort(E+1,E+1+Edge,cmp);
int EDGE=0;
for (int i=1;i<=Edge;++i){
int fa=getf(E[i].x),fb=getf(E[i].y);
if (fa>fb) fa^=fb,fb^=fa,fa^=fb;
if (fa!=fb) f[fa]=fb,b[++EDGE]=i;
}
for (int i=1;i<=EDGE;++i) f[E[b[i]].x]=E[b[i]].x,f[E[b[i]].y]=E[b[i]].y;
for (int i=1;i<=EDGE;++i)
if (E[b[i]].w!=-inf){
int fa=getf(E[b[i]].x),fb=getf(E[b[i]].y);
if (fa>fb) fa^=fb,fb^=fa,fa^=fb;
Ans+=E[b[i]].w,f[fa]=fb;
}
EDGE=0;
for (int i=1;i<=Edge;++i){
int fa=getf(E[i].x),fb=getf(E[i].y);
if (fa!=fb) b[++EDGE]=i;
}
for (int i=1;i<=EDGE;++i){
E[i]=(node){f[E[b[i]].x],f[E[b[i]].y],E[b[i]].w,E[b[i]].rk};
rk[E[i].rk]=i;
}
Edge=EDGE;
for (int i=l;i<=r;++i) E[rk[q[i].x]].w=inf;//无限小时大于r的rk被放在最后即使被删除也不会影响
for (int i=1;i<=Edge;++i) f[E[i].x]=E[i].x,f[E[i].y]=E[i].y;
sort(E+1,E+1+Edge,cmp),EDGE=0;
for (int i=1;i<=Edge;++i){
int fa=getf(E[i].x),fb=getf(E[i].y);
if (fa>fb) fa^=fb,fb^=fa,fa^=fb;
if (fa!=fb) f[fa]=fb,b[++EDGE]=i;
else if (E[i].w==inf) b[++EDGE]=i;
}
for (int i=1;i<=EDGE;++i){
E[i]=(node){E[b[i]].x,E[b[i]].y,E[b[i]].w,E[b[i]].rk};
rk[E[i].rk]=i;
}
Edge=EDGE;
for (int i=1;i<=Edge;++i) e[dep+1][i]=E[i];
int mid=(l+r)>>1;
edge[dep+1]=Edge,ans[dep+1]=Ans;
dfs(dep+1,l,mid),dfs(dep+1,mid+1,r);
}
int main(){
n=iut(),m=iut(),Q=iut();
for (int i=1;i<=m;++i)
e[0][i]=(node){iut(),iut(),w[i]=iut(),i};
for (int i=1;i<=Q;++i) q[i]=(rec){iut(),iut()};
edge[0]=m,dfs(0,1,Q);
return 0;
}
#分治,Kruskal#洛谷 3206 [HNOI2010]城市建设的更多相关文章
- 洛谷P3206 [HNOI2010]城市建设
神仙题 题目大意: 有一张\(n\)个点\(m\)条边的无向联通图,每次修改一条边的边权,问每次修改之后这张图的最小生成树权值和 话说是不是\(cdq\)题目都可以用什么数据结构莽过去啊-- 这道题目 ...
- Luogu 3206 [HNOI2010]城市建设
BZOJ 2001 很神仙的cdq分治 先放论文的链接 顾昱洲_浅谈一类分治算法 我们考虑分治询问,用$solve(l, r)$表示询问编号在$[l, r]$时的情况,那么当$l == r$的时候 ...
- 【BZOJ2001】[HNOI2010]城市建设(CDQ分治,线段树分治)
[BZOJ2001][HNOI2010]城市建设(CDQ分治,线段树分治) 题面 BZOJ 洛谷 题解 好神仙啊这题.原来想做一直不会做(然而YCB神仙早就切了),今天来怒写一发. 很明显这个玩意换种 ...
- 【LG3206】[HNOI2010]城市建设
[LG3206][HNOI2010]城市建设 题面 洛谷 题解 有一种又好想.码得又舒服的做法叫线段树分治+\(LCT\) 但是因为常数过大,无法跑过此题. 所以这里主要介绍另外一种玄学\(cdq\) ...
- [HNOI2010]城市建设
[HNOI2010]城市建设 玄学cdq O(nlog^2n)的动态最小生成树 其实就是按照时间cdq分治+剪枝(剪掉一定出现和不可能出现的边) 处理[l,r]之间的修改以及修改之后的询问,不能确定是 ...
- [洛谷P3761] [TJOI2017]城市
洛谷题目链接:[TJOI2017]城市 题目描述 从加里敦大学城市规划专业毕业的小明来到了一个地区城市规划局工作.这个地区一共有ri座城市,<-1条高速公路,保证了任意两运城市之间都可以通过高速 ...
- 【经典DP】洛谷 P2782 友好城市
嘤嘤嘤,昨天两个文化课老师在上奥赛时招呼我(亲切交流),今天又要写工作报告,没时间写题解,希望今天能补上 友好城市 题目://洛谷那粘来的题面竟然能把格式粘过来 题目描述 有一条横贯东西的大河,河有笔 ...
- 洛谷 P2120 [ZJOI2007] 仓库建设
链接: P2120 题意: 有 \(n\) 个点依次编号为 \(1\sim n\).给出这 \(n\) 个点的信息,包括位置 \(x_i\),所拥有的的物品数量 \(p_i\),在此建设一个仓库的费用 ...
- 洛谷P3203 [HNOI2010]弹飞绵羊(LCT,Splay)
洛谷题目传送门 关于LCT的问题详见我的LCT总结 思路分析 首先分析一下题意.对于每个弹力装置,有且仅有一个位置可以弹到.把这样的一种关系可以视作边. 然后,每个装置一定会往后弹,这不就代表不存在环 ...
- Bzoj2002/洛谷P3203 [HNOI2010]弹飞绵羊(分块)
题面 Bzoj 洛谷 题解 大力分块,分块大小\(\sqrt n\),对于每一个元素记一下跳多少次能跳到下一个块,以及跳到下一个块的哪个位置,修改的时候时候只需要更新元素所在的那一块即可,然后询问也是 ...
随机推荐
- 阿里云 SMS 短信 Java SDK 封装
Github & Issues: https://github.com/cn-src/aliyun-sms 官方文档:https://help.aliyun.com/document_deta ...
- 混合类Mixins介绍
介绍 混合类是封装了一些通用行为的基类,旨在重用代码.通常,混合类本身并没有什么用,仅扩展这种类也行不通 因为在大多数情况下,它都依赖于其它类中定义的方法和属性.通过多继承,可将混合类与其它类一起使用 ...
- 【C++ OOP 01】封装
封装 封装的意义 封装是C++面向对象三大特性之一 封装的意义: 将属性和行为作为一个整体,表现生活中的事物 将属性和行为加以权限控制 封装意义一 在设计类的时候,属性和行为写在一起,表现事物 语 ...
- 【Azure 应用程序见解】在Docker中运行的ASP.NET Core应用如何开启Application Insights的Profiler Trace呢?
问题描述 使用Azure Application Insights收集AKS中ASP.NET Core应用的监控数据,自动收集请求的Trace情况,用于分析单个请求在应用内部的耗时及处理事件情况,参考 ...
- UG474
为了对工程的资源利用率进行优化,我们首先需要知道当前工程对资源的利用率情况.在Vivado下,我们可以查看工程的资源利用率情况,在下面这张图中,其罗列出了整个工程所使用的资源情况.首先,下面我们需要一 ...
- c语言四则运算小程序
本文源程序代码来源于csdn一位博主: 文章链接:http://t.csdnimg.cn/L29fs 原程序简洁凝练,以简短的代码写出了一个加法运算器. 以下是运行结果(本文全程用visual stu ...
- CodeCraft-22 and Codeforces Round 795 (Div. 2)C. Sum of Substrings(分类讨论、贪心)
感觉分类讨论的能有点弱.遇到复杂一点的分类讨论的题目,代码就写的巨长. 首先观察到处在中间位置的1对答案的贡献是11,具体在中间哪个位置是没有关系的. 只有两端的两个位置是比较特殊的 \(1位置处的1 ...
- vite 子项目 热部署 通过nginx,和父项目端口号不同,导致热更新的websocket报错的解决方案
vite 子项目 热部署 通过nginx,和父项目端口号不同,导致热更新的websocket报错的解决方案 我的父项目端口号是8888 子项目端口号是 8013 这里报错的原因就是,热更新的webso ...
- 加载远程vue文件 vue3-sfc-loader
需求 项目在写一些需求的时候,现场可能会有些变动,但是不想从新打包,这种情况可以考虑单独不打包的vue文件 注意vue2 import { loadModule } from 'vue3-sfc-lo ...
- k8s资源管理之ResourceQuota、LimitRange和QoS
ResourceQuota ResourceQuota 是 Kubernetes 中的一个资源配额对象,用于限制命名空间(Namespace)中资源的使用量.ResourceQuota 可以限制命名空 ...