[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] 插入了一条边- 然后删的边和加的 ...
随机推荐
- SpringMVC之入门程序
SpringMVC之入门程序——使用浏览器展示商品数据 springMVC执行流程(图片来源:https://www.jianshu.com/p/8a20c547e245) 1.创建pojo(商品实体 ...
- Nginx配置了解
安装Nginx常用编译选项说明 nginx大部分常用模块,编译时./configure --help查看,以--without开头的都是默认安装. --prefix=PATH 指定nginx的安装目录 ...
- Markdown 7min快速入门
目录 概述 宗旨 兼容 特殊字符自动换行 区块元素 段落和换行 标题 区块引用 列表 代码区块 分隔线 区段元素 链接 强调 代码 图片 其他 表格 删除线 注脚 锚点 反斜杠 自动链接 参考文献 正 ...
- 使用Android服务,实现报警管理器和广播接收器
介绍 几乎在所有平台上都有很多进程运行背景,它们被称为服务.可能在Android平台中有一些服务可以执行长时间运行的操作,这些操作在处理时不需要用户交互. 在本文中,借助预定义的Android警报服务 ...
- SpringBoot+MyBatis配置多数据源
SpringBoot 可以支持多数据源,这是一个非常值得学习的功能,但是从现在主流的微服务的架构模式中,每个应用都具有唯一且准确的功能,多数据源的需求很难用到,考虑到实际情况远远比理论复杂的多,这里还 ...
- 服务器部署Apache+PHP+MYSQL+Laravel
1.安装PHP 添加php安装源: sudo apt-get install python-software-properties sudo add-apt-repository ppa:ondrej ...
- 利用Navicat高效率postgresql转mysql数据库
本人很喜欢postgresql数据库,也一直认为postgresql比mysql要更好更强大. 可生态环境太差了,无奈,最近要把一个小站转成mysql数据库. 小站主要表数据110万,pg_dump备 ...
- [已解决]报错:Required request body is missing
问题代码: res = requests.post(getXxxxList_url, headers=headers, data={}) 对象网站: angular4 apache 通过验证 (coo ...
- python学习——读取染色体长度(一、简化问题)
# 读取fasta # 解析每条序列的长度 chr1_len = 10 chr2_len = 20 chr3_len = 30 chr4_len = 40 chr5_len = 50 # 求和 tot ...
- Linux新增和删除环境变量
vi ~/.bashrc 添加 export 变量名=值 使环境变量生效 source ~/.bashrc