热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

开发笔记:城市建设

本文由编程笔记#小编为大家整理,主要介绍了城市建设相关的知识,希望对你有一定的参考价值。本文涉及:cdq分治、MST一道十分精妙的cdq分
本文由编程笔记#小编为大家整理,主要介绍了城市建设相关的知识,希望对你有一定的参考价值。

本文涉及:cdq分治、MST

一道十分精妙的cdq分治题(o゜▽゜)o。据说线段树分治+LCQ维护MST也是一种解法,但我并不会...

1 题意

给定一个(n)个点,(m)条边的无向带边权的图,和(q)次询问;每一次询问会修改一条边的边权;在每一次询问后求出当前图的最小生成树的权值。

数据范围:(nleq2000,m,qleq 5000)

2 解法

这道题的暴力十分显然,固不再赘述。

设函数(solve(l,r)),表示处理修改序列([l,r])中的修改;动态边表示与修改序([l,r])中的修改有关的边;反之,静态边表示与这段修改无关的边。

对于动态边我们暂且不加以考虑,因为随着函数的递归运行,动态边将不断地变化为静态边;反观静态边,它们从定为静态边起身份就不再发生改变。因为我们接下来将着重讨论如何通过必选边和无用边的划分,简化静态边边集。

必选边:将动态边的边权设为(-infty),求一次MST,此时MST中除边权为(-infty)外的边都是必选边

将一条边设为(-infty),在MST中就会优先考虑这条边。动态边都被设为了(-infty),但仍然有静态边被选中,说明动态边集不能保证图的连通,只有依赖这些静态边,图才能是连通的。根据MST的选取规则,选中的这些静态边又是所有可行方案中最优的,因此是必选边

对于必选边,将边的两个端点缩在一起后,累加边权。

无用边:将动态边的边权设为(infty),求一次MST,此时没有出现在MST中的静态边是无用边

相比必选边,此时动态边的地位一落千丈。此时没有被选中的静态边在动态边边权恢复正常后更加不可能被选上,因此是无用边。

对于无用边嘛,丢了就好╰( ̄ω ̄o)

对于某一函数([l,r]),其递归函数([l,mid])([mid+1,r])的静态边集必包含了它自身的静态边集,因此不会因为简化当前边集而出错。

每层分治时,用上述两种方法缩小图的规模;在最后一层使修改生效,求一遍MST和累加值求和即是答案。此时图的规模已经不大,可以放心kruskal。

因为分治的顺序,在处理([l,r])时,区间([1,l-1])中的修改已被落实,如下图:
技术图片
这一点是我当时的理解难点

3 代码

#include
using namespace std;
#define lor(a,b,c) for(register int a=b;a<=c;++a)
#define ror(a,b,c) for(register int a=c;a>=b;--a)
typedef long long ll;
const int MAXN=2e4+5,MAXM=5e4+5,MAXD=17;
const ll INF=5e10+5;
int n,m,q; int qid[MAXM]; ll qval[MAXM];
ll ans[MAXM]; bool ban[MAXM];
struct data{
int x,y,id; ll z,bac;
inline bool operator <(data b) const{
return z }
}info[MAXM],work[MAXD][MAXM],up[MAXM];
inline bool cmpf(data a,data b) {return ban[a.id]==ban[b.id]?a.zban[b.id];}
inline bool cmpb(data a,data b) {return ban[a.id]==ban[b.id]?a.zint fat[MAXN]; bool vis[MAXM];
inline void clear() {lor(i,1,n) fat[i]=i;}
inline int find(int a) {while(a^fat[a]) a=fat[a]=fat[fat[a]]; return a;}
inline bool unionn(int a,int b) {int aa=find(a),bb=find(b); return aa==bb?(false):(fat[aa]=bb,true);}
void cdq(int,int,int,int,ll);
inline ll vital(int,int,int,int&);
inline void radish(int,int,int,int&);
int main(){
#ifndef ONLINE_JUDGE
freopen("test.in","r",stdin);
freopen("test.out","w",stdout);
#endif
scanf("%d%d%d",&n,&m,&q);
lor(i,1,m) scanf("%d%d%lld",&info[i].x,&info[i].y,&info[i].z),info[i].id=i;
lor(i,1,q) scanf("%d%lld",&qid[i],&qval[i]);
lor(i,1,m) work[0][i]=info[i];
cdq(1,1,q,m,0);
lor(i,1,q) printf("%lld
",ans[i]);
return 0;
}
void cdq(int dep,int l,int r,int s,ll v){
if(l==r) {info[qid[l]].z=qval[l];}
lor(i,1,s) {work[dep][i]=work[dep-1][i]; work[dep][i].z=info[work[dep][i].id].z;}
if(l==r){
ans[l]=v; clear();
sort(work[dep]+1,work[dep]+1+s);
lor(i,1,s) if(unionn(work[dep][i].x,work[dep][i].y)) ans[l]+=work[dep][i].z;
return;
}
v+=vital(dep,l,r,s);
radish(dep,l,r,s);
int mid=(l+r)>>1; cdq(dep+1,l,mid,s,v); cdq(dep+1,mid+1,r,s,v);
}
inline ll vital(int dep,int l,int r,int &s){
lor(i,l,r) ban[qid[i]]=true;
ll ans=0; int tmp=0; lor(i,1,s) vis[i]=false;
sort(work[dep]+1,work[dep]+1+s,cmpf);
lor(i,1,s){
if(unionn(work[dep][i].x,work[dep][i].y)) vis[i]=true;
}
lor(i,1,s){
fat[work[dep][i].x]=work[dep][i].x; fat[work[dep][i].y]=work[dep][i].y;
}
lor(i,1,s) if(!ban[work[dep][i].id]&&vis[i]){
unionn(work[dep][i].x,work[dep][i].y); ans+=work[dep][i].z;
}
lor(i,1,s){
if(ban[work[dep][i].id]||!vis[i]){
work[dep][i].x=find(work[dep][i].x); work[dep][i].y=find(work[dep][i].y);
up[++tmp]=work[dep][i];
}
}
lor(i,1,s) if(!ban[work[dep][i].id]&&vis[i]){
fat[work[dep][i].x]=work[dep][i].x; fat[work[dep][i].y]=work[dep][i].y;
}
s=tmp; lor(i,1,s) work[dep][i]=up[i];
lor(i,l,r) ban[qid[i]]=false;
return ans;
}
inline void radish(int dep,int l,int r,int &s){
lor(i,l,r) ban[qid[i]]=true;
int tmp=0; lor(i,1,s) vis[i]=false;
sort(work[dep]+1,work[dep]+1+s,cmpb);
lor(i,1,s){
if(unionn(work[dep][i].x,work[dep][i].y)) vis[i]=true;
}
lor(i,1,s){
fat[work[dep][i].x]=work[dep][i].x; fat[work[dep][i].y]=work[dep][i].y;
}
lor(i,1,s){
if(ban[work[dep][i].id]||vis[i]){
up[++tmp]=work[dep][i];
}
}
s=tmp; lor(i,1,s) work[dep][i]=up[i];
lor(i,l,r) ban[qid[i]]=false;
}



推荐阅读
  • 本题探讨了在大数据结构背景下,如何通过整体二分和CDQ分治等高级算法优化处理复杂的时间序列问题。题目设定包括节点数量、查询次数和权重限制,并详细分析了解决方案中的关键步骤。 ... [详细]
  • 在进行QT交叉编译时,可能会遇到与目标架构不匹配的宏定义问题。例如,当为ARM或MIPS架构编译时,需要确保使用正确的宏(如QT_ARCH_ARM或QT_ARCH_MIPS),而不是默认的QT_ARCH_I386。本文将详细介绍如何正确配置编译环境以避免此类错误。 ... [详细]
  • 本题来自WC2014,题目编号为BZOJ3435、洛谷P3920和UOJ55。该问题描述了一棵不断生长的带权树及其节点上小精灵之间的友谊关系,要求实时计算每次新增节点后树上所有可能的朋友对数。 ... [详细]
  • Linux环境下C语言实现定时向文件写入当前时间
    本文介绍如何在Linux系统中使用C语言编程,实现在每秒钟向指定文件中写入当前时间戳。通过此示例,读者可以了解基本的文件操作、时间处理以及循环控制。 ... [详细]
  • Linux环境下进程间通信:深入解析信号机制
    本文详细探讨了Linux系统中信号的生命周期,从信号生成到处理函数执行完毕的全过程,并介绍了信号编程中的注意事项和常见应用实例。通过分析信号在进程中的注册、注销及处理过程,帮助读者理解如何高效利用信号进行进程间通信。 ... [详细]
  • 本题要求在一组数中反复取出两个数相加,并将结果放回数组中,最终求出最小的总加法代价。这是一个经典的哈夫曼编码问题,利用贪心算法可以有效地解决。 ... [详细]
  • JSOI2010 蔬菜庆典:树结构中的无限大权值问题
    本文探讨了 JSOI2010 的蔬菜庆典问题,主要关注如何处理非根非叶子节点的无限大权值情况。通过分析根节点及其子树的特性,提出了有效的解决方案,并详细解释了算法的实现过程。 ... [详细]
  • Qt QTableView 内嵌控件的实现方法
    本文详细介绍了在 Qt QTableView 中嵌入控件的多种方法,包括使用 QItemDelegate、setIndexWidget 和 setIndexWidget 结合布局管理器。每种方法都有其适用场景和优缺点。 ... [详细]
  • 本文介绍如何利用栈数据结构在C++中判断字符串中的括号是否匹配。通过顺序栈和链栈两种方式实现,并详细解释了算法的核心思想和具体实现步骤。 ... [详细]
  • 本文介绍如何从字符串中移除大写、小写、特殊、数字和非数字字符,并提供了多种编程语言的实现示例。 ... [详细]
  • 在高并发需求的C++项目中,我们最初选择了JsonCpp进行JSON解析和序列化。然而,在处理大数据量时,JsonCpp频繁抛出异常,尤其是在多线程环境下问题更为突出。通过分析发现,旧版本的JsonCpp存在多线程安全性和性能瓶颈。经过评估,我们最终选择了RapidJSON作为替代方案,并实现了显著的性能提升。 ... [详细]
  • 深入解析Spring启动过程
    本文详细介绍了Spring框架的启动流程,帮助开发者理解其内部机制。通过具体示例和代码片段,解释了Bean定义、工厂类、读取器以及条件评估等关键概念,使读者能够更全面地掌握Spring的初始化过程。 ... [详细]
  • 在尝试使用C# Windows Forms客户端通过SignalR连接到ASP.NET服务器时,遇到了内部服务器错误(500)。本文将详细探讨问题的原因及解决方案。 ... [详细]
  • 主调|大侠_重温C++ ... [详细]
  • 本文详细介绍了C语言中的基本数据类型,包括整型、浮点型、字符型及其各自的子类型,并探讨了这些类型在不同编译环境下的表现。 ... [详细]
author-avatar
黑糖老姜茶
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有