[HNOI2010]城市建设
玄学cdq
O(nlog^2n)的动态最小生成树
其实就是按照时间cdq分治+剪枝(剪掉一定出现和不可能出现的边)
处理[l,r]之间的修改以及修改之后的询问,不能确定是否加入的边集为E
对于会被改变边权的边,边集为Q,暂时不能确定
不妨大力假设:
都是-inf,这个时候把Q的边都加入之后,剩下的E进行kruskal如果还能加入,那么在[l,r]这个区间里的所有询问,一定都能加进去
并查集带着必须边,然后处理Q都是inf,剩下的E进行kruskal,如果还是不能加入,那么在[l,r]这个区间里的所有询问,一定都不会加进去
这样,Q和第二次能加进去的边继续往左右递归,继续确定。
到了l==r时候,
把这个修改生效(因为之后再考虑的时候边权一定已经变了)
暴力把E中的边进行kruskal即可。
按秩合并并查集撤销,有些必须边出了[l,r]可能就被替换了。
说白了就是,cdq分治,强行维护备选边集+大力剪枝
感性理解一下复杂度:
看做n,m,q同阶
当Q中的边集最分散的时候,也就是形成一棵树,此时能确定的边是最少的。
这样,每次len/2,那么至少会多确定len/2个边(解放了n/2个点)
规模大概/=2
实际应该远不到上界,但是sort常数很大
O(nlog^2n)
注意,并查集不要随手写成路径压缩!!!
// luogu-judger-enable-o2
// luogu-judger-enable-o2
#include<bits/stdc++.h>
#define reg register int
#define il inline
#define fi first
#define se second
#define mk(a,b) make_pair(a,b)
#define numb (ch^'0')
#define pb push_back
#define solid const auto &
#define enter cout<<endl
using namespace std;
typedef long long ll;
template<class T>il void rd(T &x){
char ch;x=;bool fl=false;
while(!isdigit(ch=getchar()))(ch=='-')&&(fl=true);
for(x=numb;isdigit(ch=getchar());x=x*+numb);
(fl==true)&&(x=-x);
}
template<class T>il void output(T x){if(x/)output(x/);putchar(x%+'');}
template<class T>il void ot(T x){if(x<) putchar('-'),x=-x;output(x);putchar(' ');}
template<class T>il void prt(T a[],int st,int nd){for(reg i=st;i<=nd;++i) ot(a[i]);putchar('\n');} namespace Miracle{
const int N=+;
int n,m,q;
struct edge{
int x,y,w;
bool friend operator <(edge a,edge b){
return a.w<b.w;
}
}E[N];
bool cmp(int x,int y){
return E[x]<E[y];
}
struct qs{
int id,w;
}Q[N];
ll ans[N];
int fa[N],sz[N];
int exi[N],tag;
int fin(int x){return fa[x]==x?x:fin(fa[x]);}
vector<pair<int *,int> >buc;
void push(int &x,int v){buc.push_back(mk(&x,x));x=v;}
void roll(int t){
while((int)buc.size()>t) *buc.back().fi=buc.back().se,buc.pop_back();
}
void merge(int x,int y){
x=fin(x);y=fin(y);
if(x==y) return;
if(sz[x]>sz[y]) swap(x,y);
push(fa[x],y);push(sz[y],sz[x]+sz[y]);
}
void wrk(vector<int> &e,int l,int r,ll &val){
int st=buc.size();
static vector<int>tmp;tmp.clear();
sort(e.begin(),e.end(),cmp);
for(reg i=l;i<=r;++i) merge(E[Q[i].id].x,E[Q[i].id].y);
for(solid i:e){
if(exi[i]==tag) continue;
int x=fin(E[i].x),y=fin(E[i].y);
if(x!=y){
merge(x,y);val+=E[i].w;tmp.pb(i);
}
}
roll(st);
for(solid i:tmp){
merge(E[i].x,E[i].y);
}
}
void dele(vector<int> &e){
vector<int>tmp;
sort(e.begin(),e.end(),cmp);
int st=buc.size();
for(solid i:e){
if(exi[i]==tag){
tmp.pb(i);continue;
}
int x=fin(E[i].x),y=fin(E[i].y);
if(x!=y){
merge(x,y);tmp.pb(i);
}
}
roll(st);
e.swap(tmp);
}
void sol(int l,int r,vector<int>e,ll val){
// cout<<" l "<<l<<" r "<<r<<" val "<<val<<endl;
// for(solid i:e){
// cout<<i<<" ";
// }enter;
if(l==r) E[Q[l].id].w=Q[l].w;
int st=buc.size();
if(l==r){
sort(e.begin(),e.end(),cmp);
for(solid i:e){
int x=fin(E[i].x),y=fin(E[i].y);
if(x!=y){
merge(x,y);val+=E[i].w;
}
}
ans[l]=val;
}else{
++tag;
for(reg i=l;i<=r;++i) exi[Q[i].id]=tag;
wrk(e,l,r,val);
dele(e);
int mid=(l+r)>>;
sol(l,mid,e,val);sol(mid+,r,e,val);
}
roll(st);
}
int main(){
rd(n);rd(m);rd(q);
vector<int>st;
for(reg i=;i<=m;++i){
rd(E[i].x);rd(E[i].y);rd(E[i].w);
st.push_back(i);
}
for(reg i=;i<=n;++i) fa[i]=i,sz[i]=;
for(reg i=;i<=q;++i){
rd(Q[i].id);rd(Q[i].w);
}
sol(,q,st,);
for(reg i=;i<=q;++i){
printf("%lld\n",ans[i]);
}
return ;
} }
signed main(){
Miracle::main();
return ;
} /*
Author: *Miracle*
*/
[HNOI2010]城市建设的更多相关文章
- 【BZOJ2001】[HNOI2010]城市建设(CDQ分治,线段树分治)
[BZOJ2001][HNOI2010]城市建设(CDQ分治,线段树分治) 题面 BZOJ 洛谷 题解 好神仙啊这题.原来想做一直不会做(然而YCB神仙早就切了),今天来怒写一发. 很明显这个玩意换种 ...
- 【LG3206】[HNOI2010]城市建设
[LG3206][HNOI2010]城市建设 题面 洛谷 题解 有一种又好想.码得又舒服的做法叫线段树分治+\(LCT\) 但是因为常数过大,无法跑过此题. 所以这里主要介绍另外一种玄学\(cdq\) ...
- BZOJ2001 HNOI2010 城市建设
题目大意:动态最小生成树,可以离线,每次修改后回答,点数20000,边和修改都是50000. 顾昱洲是真的神:顾昱洲_浅谈一类分治算法 链接: https://pan.baidu.com/s/1c2l ...
- BZOJ2001 HNOI2010城市建设(线段树分治+LCT)
一个很显然的思路是把边按时间段拆开线段树分治一下,用lct维护MST.理论上复杂度是O((M+Q)logNlogQ),实际常数爆炸T成狗.正解写不动了. #include<iostream> ...
- [HNOI2010] 城市建设_动态最小生成树(Dynamic_MST)
这个题...暴力单次修改\(O(n)\),爆炸... $ $ 不过好在可以离线做 如果可以在 分治询问 的时候把图缩小的话就可以做了 硬着头皮把这个骚东西看完了 $ $ 动态最小生成树 然后,就把它当 ...
- 【CDQ分治】[HNOI2010]城市建设
题目链接 线段树分治+LCT只有80 然后就有了CDQ分治的做法 把不可能在生成树里的扔到后面 把一定在生成树里的扔到并查集里存起来 分治到l=r,修改边权,跑个kruskal就行了 由于要支持撤销, ...
- Luogu 3206 [HNOI2010]城市建设
BZOJ 2001 很神仙的cdq分治 先放论文的链接 顾昱洲_浅谈一类分治算法 我们考虑分治询问,用$solve(l, r)$表示询问编号在$[l, r]$时的情况,那么当$l == r$的时候 ...
- 洛谷P3206 [HNOI2010]城市建设
神仙题 题目大意: 有一张\(n\)个点\(m\)条边的无向联通图,每次修改一条边的边权,问每次修改之后这张图的最小生成树权值和 话说是不是\(cdq\)题目都可以用什么数据结构莽过去啊-- 这道题目 ...
- P3206 [HNOI2010]城市建设 [线段树分治+LCT维护动态MST]
Problem 这题呢 就边权会在某一时刻变掉-众所周知LCT不支持删边的qwq- 所以考虑线段树分治- 直接码一发 如果 R+1 这个时间修改 那就当做 [L,R] 插入了一条边- 然后删的边和加的 ...
随机推荐
- Struts2中五个重要的常量
一.五个常量的位置:位于xwork核心包下的Action字节码文件里 二.五个常量的介绍: a: SUCCESS public static final String SUCCESS = " ...
- 2016年第七届蓝桥杯javaB组 试题 答案 解析
1.煤球数目 有一堆煤球,堆成三角棱锥形.具体: 第一层放1个, 第二层3个(排列成三角形), 第三层6个(排列成三角形), 第四层10个(排列成三角形), .... 如果一共有100层,共有多少个煤 ...
- dbutils工具类使用
1DBUtils工具类 1.1概述 DBUtils是java编程中的数据库操作实用工具,小巧简单实用. DBUtils封装了对JDBC的操作,简化了JDBC操作,可以少写代码 DBUtils三个核心功 ...
- element表格添加序号
表格代码:黄色部分为序号列关键代码上图: <el-table :data="tableData" border height="480" style=&q ...
- Snapde电子表格支持的文件格式
Snapde,一个专门为编辑超大型数据量CSV文件而设计的单机版电子表格软件:它运行的速度非常快,反应非常灵敏.那么它支持哪些文件格式呢? 1.CSV文件格式,是一种以逗号分隔列.以回车分隔行的文本文 ...
- Android为TV端助力 使用shared注意事项
不要存放大的key和value!我就不重复三遍了,会引起界面卡.频繁GC.占用内存等等,好自为之! 毫不相关的配置项就不要丢在一起了!文件越大读取越慢,不知不觉就被猪队友给坑了:蓝后,放进defalu ...
- Spring AOP 整理笔记
一.AOP概念 AOP为Aspect Oriented Programming的缩写,意为:面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术. 利用AOP可以对业务逻辑的各 ...
- 斐波那契数列(C#)
斐波那契数,亦称之为斐波那契数列(意大利语: Successione di Fibonacci),又称黄金分割数列.费波那西数列.费波拿契数.费氏数列,指的是这样一个数列:1.1.2.3.5.8.13 ...
- SQLServer之创建提交读
事务提交读注意事项 语法:set transaction isolation level read committed. 数据库默认的是两个会话事务之间是提交读. READ COMMITTED指定语句 ...
- Linux学习之路(三)Shell脚本初探
本文参考链接:http://www.runoob.com/linux/linux-shell.html 基本说明 Shell脚本(shell script)是一种为shell编写的脚本程序.其中she ...