问题描述:

PS国是一个拥有诸多城市的大国,国王Louis为城市的交通建设可谓绞尽脑汁。
Louis可以在某些城市之间修建道路,在不同的城市之间修建道路需要不同的花费。
Louis希望建造最少的道路使得国内所有的城市连通。
但是由于某些因素,城市之间修建道路需要的花费会随着时间而改变,Louis会不断得到某道路的修建代价改变的消息,他希望每得到一条消息后能立即知道使城市连通的最小花费总和,Louis决定求助于你来完成这个任务。

输入格式:

第一行包含三个整数N,M,Q,分别表示城市的数目,可以修建的道路个数,及收到的消息个数。
接下来有M行,第i+1行有三个用空格隔开的整数Xi,Yi,Zi(1<=Xi,Yi<=N, 0<=Zi<=5*10^7),表示在城市Xi与城市Yi之间修建道路的代价为Zi。
接下来Q行,每行包含两个数k,d,表示输入的第k个道路的修建代价修改为d(即将Zi修改为d)。

输出格式:

包含Q行,第i行输出得知前i条消息后使城市连通的最小花费总和。

数据范围:

对于20%的数据, n≤1000,m≤6000,Q≤6000。
另有20%的数据,n≤1000,m≤50000,Q≤8000,修改后的代价不会比之前的代价低。
对于100%的数据, n≤20000,m≤50000,Q≤50000。

  一道奇奇怪怪的题,为什么会是CDQ啊(刷新认知)。但,既然ta是那ta就是吧。

  读完题,应该知道有最小生成树,所以现在我们知道 ta 是 MST + CDQ

  但ta的图是会变的,如果每次都跑一次 Kruskal 肯定是不行的,那怎么优化呢?

  

   因为 CDQ 所以一定是离线的,对于一个修改区间 [ L , R ] ,可以把边分为三类:

      ① 一定有用的边,即一定在 MST 上的边;

      ② 一定没有用的边,即一定不在 MST 上的边;

      ③ 不一定有用的边,即不一定在 MST 上的边。

    对于①而言,可以把相连的点缩为一个点;对于②而言,可以把无用边删去。这样缩点、删边后图的规模会越来越小。

  之后再处理  [ L , M ] 和 [ M + 1 , R ] 区间(M = ( L + R ) >> 1)。

  怎么实现呢?

  对于一个修改区间 [ L , R ] 的边全部设为  -inf  ,求一次MST,MST上的点是一定有用的边;对于一个修改区间 [ L , R ] 的边全部设为 inf  ,求一次MST,MST上的点是一定没用的边。

  这两点真的很好证明,读者自证不难。

  还是YY一哈,当区间 [ L , R ] 的边全部为  -inf 时,跑MST的时候,他们一定是优先选择的,如果还有其他边被选,那么这些边一定是会出现在接下来的MST中的;Vice Versa。

     

  值得注意的是:CDQ过程中,只是用来减少边数的,真正的修改边权,是在 L == R 时进行的。

  当然,并查集是必不可少的,要维护连通性嘛,但因为要存的数据太大了,并查集需要实现 可撤销 。具体而言,由于树深是不会超过20的,可以开20个来分别存储,即分层。

  更多细节可参考代码。

Code:

#pragma GCC optimize(2)
#pragma GCC optimize(3)
#include<bits/stdc++.h>
#define inf 1e9
using namespace std;
int n,m,q,Fa[50005],A[50005],B[50005],C[50005],Deep[21];
long long Ans[50005];
struct node {int x,y,z,Id;}E[21][50005],Tmp[50005],Temp[50005];
bool cmp(node a,node b) {return a.z<b.z;}
struct nodden {int k,d;}Q[50005];
#define gc (p1==p2&&(p2=(p1=buf)+fread(buf,1,65536,stdin),p1==p2)?EOF:*p1++)
char buf[65536],*p1,*p2;
inline int read()
{
char ch;int x(0);
while((ch=gc)<48);
do x=x*10+ch-48;while((ch=gc)>=48);
return x;
}
inline int GetFa(int x) {return (Fa[x]==x)?x:Fa[x]=GetFa(Fa[x]);}
inline void Link(int x,int y)
{
x=GetFa(x),y=GetFa(y);if(x==y) return;
if(B[x]!=B[y]) (B[x]>B[y])?Fa[y]=x:Fa[x]=y;
else Fa[x]=y,++B[y];
}
inline void Find1(int &x,long long &V)
{
int head(0);
for(register int i=1;i<=x;++i) Fa[Tmp[i].x]=Tmp[i].x,Fa[Tmp[i].y]=Tmp[i].y,B[Tmp[i].x]=B[Tmp[i].y]=1;
sort(Tmp+1,Tmp+x+1,cmp);
for(register int i=1;i<=x;++i)
if(GetFa(Tmp[i].x)!=GetFa(Tmp[i].y)) Link(Tmp[i].x,Tmp[i].y),Temp[++head]=Tmp[i];
for(register int i=1;i<=head;++i) Fa[Temp[i].x]=Temp[i].x,Fa[Temp[i].y]=Temp[i].y,B[Temp[i].x]=B[Temp[i].y]=1;
for(register int i=1;i<=head;++i)
if(Temp[i].z!=-inf&&GetFa(Temp[i].x)!=GetFa(Temp[i].y)) Link(Temp[i].x,Temp[i].y),V+=Temp[i].z;
head=0;
for(register int i=1;i<=x;++i)
if(GetFa(Tmp[i].x)!=GetFa(Tmp[i].y)) Temp[++head]=node{GetFa(Tmp[i].x),GetFa(Tmp[i].y),Tmp[i].z,Tmp[i].Id};
for(register int i=1;i<=head;++i) C[Tmp[i].Id]=i,Tmp[i]=Temp[i];
x=head;
}
inline void Find2(int &x)
{
int head(0);
for(register int i=1;i<=x;++i) Fa[Tmp[i].x]=Tmp[i].x,Fa[Tmp[i].y]=Tmp[i].y,B[Tmp[i].x]=B[Tmp[i].y]=1;
sort(Tmp+1,Tmp+x+1,cmp);
for(register int i=1;i<=x;++i)
if(GetFa(Tmp[i].x)!=GetFa(Tmp[i].y)) Link(Tmp[i].x,Tmp[i].y),Temp[++head]=Tmp[i];
else if(Tmp[i].z==inf) Temp[++head]=Tmp[i];
for(register int i=1;i<=head;++i) C[Tmp[i].Id]=i,Tmp[i]=Temp[i];
x=head;
}
inline void CDQ(int L,int R,int deep,long long V)
{
int k=Deep[deep],M=(L+R)>>1;
if(L==R) A[Q[L].k]=Q[L].d;
for(register int i=1;i<=k;++i) E[deep][i].z=A[E[deep][i].Id],Tmp[i]=E[deep][i],C[Tmp[i].Id]=i;
if(L==R)
{
for(register int i=1;i<=k;++i) Fa[Tmp[i].x]=Tmp[i].x,Fa[Tmp[i].y]=Tmp[i].y,B[Tmp[i].x]=B[Tmp[i].y]=1;
Ans[L]=V,sort(Tmp+1,Tmp+k+1,cmp);
for(register int i=1;i<=k;++i)
if(GetFa(Tmp[i].x)!=GetFa(Tmp[i].y)) Link(Tmp[i].x,Tmp[i].y),Ans[L]+=Tmp[i].z;
return;
}
for(register int i=L;i<=R;++i) Tmp[C[Q[i].k]].z=-inf;
Find1(k,V);
for(register int i=L;i<=R;++i) Tmp[C[Q[i].k]].z=inf;
Find2(k);
for(register int i=1;i<=k;++i) E[deep+1][i]=Tmp[i];
Deep[deep+1]=k,CDQ(L,M,deep+1,V),CDQ(M+1,R,deep+1,V);
}
int main()
{
n=read(),m=read(),q=read();
for(register int i=1;i<=m;++i) E[0][i].x=read(),E[0][i].y=read(),E[0][i].z=A[i]=read(),E[0][i].Id=i;
for(register int i=1;i<=q;++i) Q[i].k=read(),Q[i].d=read();
Deep[0]=m,CDQ(1,q,0,0);
for(register int i=1;i<=q;++i) printf("%lld\n",Ans[i]);
return 0;
}

城市建设

NKOJ-2936 城市建设的更多相关文章

  1. BZOJ 2001: [Hnoi2010]City 城市建设

    2001: [Hnoi2010]City 城市建设 Time Limit: 20 Sec  Memory Limit: 162 MBSubmit: 1132  Solved: 555[Submit][ ...

  2. RFID智能感知摄像机推进智慧城市建设步伐

    随着智慧城市建设步伐的大力推进,各地的智慧城市建设取得了卓有成效的成果.物联网工程正在如火如荼地进行,顺应智慧城市物联网的发展大趋势,建设城市级的视频感知网,涉及治安.交通.教育等多方面综合传感应用, ...

  3. [HNOI2010]城市建设

    [HNOI2010]城市建设 玄学cdq O(nlog^2n)的动态最小生成树 其实就是按照时间cdq分治+剪枝(剪掉一定出现和不可能出现的边) 处理[l,r]之间的修改以及修改之后的询问,不能确定是 ...

  4. 【BZOJ2001】[HNOI2010]城市建设(CDQ分治,线段树分治)

    [BZOJ2001][HNOI2010]城市建设(CDQ分治,线段树分治) 题面 BZOJ 洛谷 题解 好神仙啊这题.原来想做一直不会做(然而YCB神仙早就切了),今天来怒写一发. 很明显这个玩意换种 ...

  5. 【BZOJ2001】 [Hnoi2010]City 城市建设

    BZOJ2001 [Hnoi2010]City 城市建设 Solution 我们考虑一下这个东西怎么求解? 思考无果...... 咦? 好像可以离线cdq,每一次判断一下如果这条边如果不选就直接删除, ...

  6. BZOJ2001 [Hnoi2010]City 城市建设 CDQ分治

    2001: [Hnoi2010]City 城市建设 Time Limit: 20 Sec  Memory Limit: 162 MB Description PS国是一个拥有诸多城市的大国,国王Lou ...

  7. 算法笔记_177:历届试题 城市建设(Java)

    目录 1 问题描述 2 解决方案   1 问题描述 问题描述 栋栋居住在一个繁华的C市中,然而,这个城市的道路大都年久失修.市长准备重新修一些路以方便市民,于是找到了栋栋,希望栋栋能帮助他. C市中有 ...

  8. 【LG3206】[HNOI2010]城市建设

    [LG3206][HNOI2010]城市建设 题面 洛谷 题解 有一种又好想.码得又舒服的做法叫线段树分治+\(LCT\) 但是因为常数过大,无法跑过此题. 所以这里主要介绍另外一种玄学\(cdq\) ...

  9. 【HNOI2010】城市建设(对时间分治 & Kruskal)

    Description \(n\) 个点 \(m\) 条边的带边权无向图.\(q\) 次操作,每次修改一条边的权值. 求每次修改后的最小生成树的边权和. Hint \(1\le n\le 2\time ...

随机推荐

  1. Spring表达式

    一.SpEL 其中,直接写也可以赋值,' ' 单引号引起来后成为一个字符串对象,可以调用String的方法: 二.引用另外一个bean 装配这个类的bean: 1.第一种方法,property标签中使 ...

  2. 配置IIS Express 允许外部访问

    修改applicationhost.config 配置允许外部访问 操作步骤: 1. 查看本机IP地址记录IP地址,例如:10.1.20.138 2. 如下图,找到要发布的站点的名称 记录站点的名称, ...

  3. Markdown时序图--基础语法

    时序图 ​ 序列图是一种交互图,它显示了流程以何种顺序相互操作. Mermaid可以渲染序列图,如下定义. sequenceDiagram Alice->>John:Message Hel ...

  4. C语言学习笔记---1.C语言概述

    1.典型C程序结构 2.C程序细节 2.1#include指令和头文件 #include这行代码是一条C预处理器指令(preprocessor directive).通常,C编译器在编译前会对源代码做 ...

  5. WPF 通过进程实现异常隔离的客户端

    当 WPF 客户端需要实现插件系统的时候,一般可以基于容器或者进程来实现.如果需要对外部插件实现异常隔离,那么只能使用子进程来加载插件,这样插件如果抛出异常,也不会影响到主进程.WPF 元素无法跨进程 ...

  6. Vue3的其他属性和API函数

    customRef() 自定义Ref函数实现Ref()的相关功能 1 <script> 2 import { ref customRef} from 'vue' 3 4 function ...

  7. 简单易行的美化方案:Ubuntu 18.04 把启动过程中的紫色美化为黑色

    背景 给笔记本装了一个Ubuntu,嫌弃启动的颜色很丑:因此在网上找到了一些修改方法,集成为一个傻瓜脚本. 参考文档: https://askubuntu.com/questions/5065/how ...

  8. @ConfigurationProperties与@Value的区别

    1. 首先我们来看每一个的具体使用 1. ConfigurationProperties 1. application.yml文件中: person: lastName: xj age: 18 bos ...

  9. 初探webpack之编写plugin

    初探webpack之编写plugin webpack通过plugin机制让其使用更加灵活,以适应各种应用场景,当然也大大增加了webpack的复杂性,在webpack运行的生命周期中会广播出许多事件, ...

  10. Django整理(五) - 请求与响应 - request对象

    请求对象 一.客户端传参的几种方式 1. 通过URL路径(path)传递,例如:http://127.0.0.1:8000/news/1/2,两个参数:id和page 2. 通过 query stri ...