[HNOI2010] 城市建设_动态最小生成树(Dynamic_MST)
这个题。。。暴力单次修改\(O(n)\),爆炸。。。
$
$
不过好在可以离线做
如果可以在 分治询问 的时候把图缩小的话就可以做了
硬着头皮把这个骚东西看完了
$
$
动态最小生成树
然后,就把它当板子写好了。。。
思路是这样的:
经过修改后会得到 \(K\) 个 \(MST\),在这些 \(MST\) 中,有些边是反复在用的,有些边是一直没有用到的
那么考虑把这些边去除掉,就能把图给缩小
关键就是这么两个东西:
\(contraction\)
处理必需边,将询问中的边权值设为 \(-inf\) ,做一遍 \(MST\) ,这时 \(MST\) 中的 非\(-inf\) 的边就是必需边
把这些边两端的点缩起来(可以用并查集维护),顺便统计一下边权和,再将其他边连回来
\(reduction\)
处理无用边将询问中的边权值设为inf,做 \(MST\) ,不在 \(MST\) 中的 非\(inf\) 的边就是无用边,可以直接删除
图片蒯自 顾昱洲_浅谈一类分治算法
$
$
这样子的话在每一层都可以去掉一些点和一些边,就能在分治询问的时候缩小图的规模
总结一下的话,大致流程就是这个样子的:
- 当前递归区间 \([l,r]\);
- 若 \(l=r\) ,暴力修改,统计答案并 \(return\);
- \(contraction\),\(reduction\);
- 递归 \([l,mid]\) , \([mid+1,r]\);
$
$
//made by Hero_of_Someone
//哎呀这个代码...懒得写归并了,排序都用 sort 凑合一下算了...
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#define N (100010)
#define ll long long
#define inf 1ll<<54
#define RG register
using namespace std;
inline int gi(){ RG int x=0,q=1; RG char ch=getchar(); while((ch<'0'||ch>'9')&&ch!='-') ch=getchar();
if(ch=='-') q=-1,ch=getchar(); while('0'<=ch&&ch<='9') x=x*10+ch-'0',ch=getchar(); return q*x; }
void File(){freopen(".in","r",stdin);freopen(".out","w",stdout);}
ll Ans[N];
int n,m,q;
int a[N],sum[54],pos[N];
struct ques{ int k,d; }que[N];
struct Edge{ int u,v,id; ll w;
inline bool operator<(const Edge& a)const{ return w<a.w; }
}e[54][N],tmp[N],t[N];
int fa[N];
inline int find(RG int x){ return fa[x]==x?x:fa[x]=find(fa[x]); }
inline void init(){
n=gi(),m=gi(),q=gi();
for(RG int i=1;i<=m;i++){
e[0][i].u=gi(),e[0][i].v=gi();
a[i]=e[0][i].w=gi();
e[0][i].id=i;
}
sum[0]=m;
for(RG int i=1;i<=q;i++)
que[i].k=gi(),que[i].d=gi();
}
inline void clear(int x){
for(RG int i=1;i<=x;i++){
fa[tmp[i].u]=tmp[i].u;
fa[tmp[i].v]=tmp[i].v;
}
}
inline void contraction(int& cnt,ll& ret){ //处理必需边
RG int num=0;
sort(tmp+1,tmp+cnt+1); clear(cnt);
for(RG int i=1;i<=cnt;i++){
RG int fx=find(tmp[i].u),fy=find(tmp[i].v);
if(fx==fy) continue;
fa[fx]=fy; t[++num]=tmp[i];
}
for(RG int i=1;i<=num;i++){
fa[t[i].u]=t[i].u;
fa[t[i].v]=t[i].v;
}
for(RG int i=1;i<=num;i++){ //将必需边两端缩起来
if(t[i].w==-inf) continue;
RG int fx=find(t[i].u),fy=find(t[i].v);
ret+=t[i].w,fa[fx]=fy;
}
num=0;
for(RG int i=1;i<=cnt;i++){ //缩点后的新图重新连边
RG int fx=find(tmp[i].u),fy=find(tmp[i].v);
if(fx==fy) continue;
t[++num]=tmp[i];
t[num].u=fx,t[num].v=fy;
pos[tmp[i].id]=num;
} cnt=num;
for(RG int i=1;i<=cnt;i++) tmp[i]=t[i];
}
inline void reduction(int& cnt){ //处理无用边
sort(tmp+1,tmp+cnt+1);
RG int num=0; clear(cnt);
for(RG int i=1;i<=cnt;i++){ //只留下当前MST中的边
RG int fx=find(tmp[i].u),fy=find(tmp[i].v);
if(fx==fy){ //待修改边也要留下
if(tmp[i].w==inf){
t[++num]=tmp[i];
pos[tmp[i].id]=num;
}
continue;
}
fa[fx]=fy;
t[++num]=tmp[i];
pos[tmp[i].id]=num;
} cnt=num;
for(RG int i=1;i<=cnt;i++) tmp[i]=t[i];
}
inline void Solve(int l,int r,int dep,ll ret){
RG int cnt=sum[dep];
if(l==r) a[ que[l].k ]=que[l].d;
for(RG int i=1;i<=cnt;i++){
e[dep][i].w=a[ e[dep][i].id ];
pos[ e[dep][i].id ]=i;
tmp[i]=e[dep][i];
}
if(l==r){
clear(cnt);
sort(tmp+1,tmp+cnt+1);
for(RG int i=1;i<=cnt;i++){
RG int fx=find(tmp[i].u),fy=find(tmp[i].v);
if(fx==fy) continue;
fa[fx]=fy; ret+=tmp[i].w;
}
Ans[l]=ret;
return ;
}
RG int mid=(l+r)>>1;
for(RG int i=l;i<=r;i++) tmp[ pos[que[i].k] ].w=-inf;
contraction(cnt,ret);
for(RG int i=l;i<=r;i++) tmp[ pos[que[i].k] ].w=inf;
reduction(cnt); sum[dep+1]=cnt;
for(RG int i=1;i<=cnt;i++) e[dep+1][i]=tmp[i];
Solve(l,mid,dep+1,ret); Solve(mid+1,r,dep+1,ret);
}
inline void work(){
Solve(1,q,0,0);
for(RG int i=1;i<=q;i++)
printf("%lld\n",Ans[i]);
}
int main(){ init(); work(); return 0; }
[HNOI2010] 城市建设_动态最小生成树(Dynamic_MST)的更多相关文章
- [HNOI2010]城市建设
[HNOI2010]城市建设 玄学cdq O(nlog^2n)的动态最小生成树 其实就是按照时间cdq分治+剪枝(剪掉一定出现和不可能出现的边) 处理[l,r]之间的修改以及修改之后的询问,不能确定是 ...
- 【BZOJ2001】[HNOI2010]城市建设(CDQ分治,线段树分治)
[BZOJ2001][HNOI2010]城市建设(CDQ分治,线段树分治) 题面 BZOJ 洛谷 题解 好神仙啊这题.原来想做一直不会做(然而YCB神仙早就切了),今天来怒写一发. 很明显这个玩意换种 ...
- 【LG3206】[HNOI2010]城市建设
[LG3206][HNOI2010]城市建设 题面 洛谷 题解 有一种又好想.码得又舒服的做法叫线段树分治+\(LCT\) 但是因为常数过大,无法跑过此题. 所以这里主要介绍另外一种玄学\(cdq\) ...
- BZOJ2001 HNOI2010 城市建设
题目大意:动态最小生成树,可以离线,每次修改后回答,点数20000,边和修改都是50000. 顾昱洲是真的神:顾昱洲_浅谈一类分治算法 链接: https://pan.baidu.com/s/1c2l ...
- P3206 [HNOI2010]城市建设 [线段树分治+LCT维护动态MST]
Problem 这题呢 就边权会在某一时刻变掉-众所周知LCT不支持删边的qwq- 所以考虑线段树分治- 直接码一发 如果 R+1 这个时间修改 那就当做 [L,R] 插入了一条边- 然后删的边和加的 ...
- Luogu 3206 [HNOI2010]城市建设
BZOJ 2001 很神仙的cdq分治 先放论文的链接 顾昱洲_浅谈一类分治算法 我们考虑分治询问,用$solve(l, r)$表示询问编号在$[l, r]$时的情况,那么当$l == r$的时候 ...
- Uoj #274. 【清华集训2016】温暖会指引我们前行 LCT维护边权_动态最小生成树
Code: 行#include<bits/stdc++.h> #define ll long long #define maxn 1000000 #define inf 100000000 ...
- 洛谷P3206 [HNOI2010]城市建设
神仙题 题目大意: 有一张\(n\)个点\(m\)条边的无向联通图,每次修改一条边的边权,问每次修改之后这张图的最小生成树权值和 话说是不是\(cdq\)题目都可以用什么数据结构莽过去啊-- 这道题目 ...
- BZOJ2001 HNOI2010城市建设(线段树分治+LCT)
一个很显然的思路是把边按时间段拆开线段树分治一下,用lct维护MST.理论上复杂度是O((M+Q)logNlogQ),实际常数爆炸T成狗.正解写不动了. #include<iostream> ...
随机推荐
- 同一个解决方案或有依赖关系的两个项目引用同名但不同版本的DLL
问题描述 我们最近在使用Redis作Session的集中化,中间碰到了一个如下问题:我们有一些项目比较老,引用了NewtonJson的4.0.3.0版本的DLL,但是Redis提供的C#集成DLL引用 ...
- C# 实现表单的自动化测试<通过程序控制一个网页>
学历代表你的过去,能力代表你的现在,学习代表你的将来 十年河东,十年河西,莫欺少年穷 学无止境,精益求精 C# 实现表单的自动化测试,这标题看着就来劲!那么,如何通过C#程序控制一个网页呢? 在此,以 ...
- 一个很好用的在线编辑、展示、分享、交流JavaScript 代码的平台
在发表博客时,有一些代码只能粘贴进去,而不能看到代码运行的效果,需要读者把代码粘贴进自己的编辑器,然后再运行看效果,这是一件很耗时的事情 在平时百度的时候,我发现一些网站可以在线预览功能,而且可以在线 ...
- Log4net_配置
Log4net 有三个主要组件:loggers,appenders 和 layouts.这三个组件一起工作使得开发者能够根据信息类型和等级(Level)记录信息,以及在运行时控制信息的格式化和信息的写 ...
- CSS 表格实例
CSS 表格实例CSS 表格属性可以帮助您极大地改善表格的外观.CSS Table 属性属性 描述border-collapse 设置是否把表格边框合并为单一的边框.border-spacing 设置 ...
- Haproxy基础知识 -运维小结
开源软件负载均衡器 现在常用的三大开源软件负载均衡器分别是Nginx.LVS.Haproxy. 在之前的文章中已经对比了这三个负载均衡软件, 下面根据自己的理解和使用经验, 再简单说下这三个负载均衡软 ...
- php类之clone 克隆
对象也能被“克隆” 在php5中,对象的传递方式默认为引用传递,如果我们想要在内存中生成两个一样的对象或者创建一个对象的副本,这时可以使用“克隆”. 通过 clone 克隆一个对象 对象的复制是通过关 ...
- 北航学堂Android客户端Beta阶段发布说明
在从学姐那里拿到服务接口的代码最终连通服务器之后,经过我们团队的努力,终于把前后端融合生成了我们目前的版本, 因为我们在Alpha阶段网络连接部分是一直没有搞定的,所以这个版本其实并不算是真正的Bet ...
- 手工编程:hello world
全部用命令行工具和Notepad编辑器,用手工创建并编译一个C的命令行程序:hello world. public class Hello{ public static void ma ...
- 在-for 循环里面如何利用ref 操作dom
由于dom 元素是在渲染之后才能操作,所以如果想取到dom元素,要放到mounted()这个生命周期函数里面,并且还要用this.$nextTick(function () {})