当前位置: 首页 > news >正文

线段树优化建图

例题链接

给定一张 \(n\) 个点的图,完成 \(q\) 次建边操作,每次建边有权值:

  • 建有向边 \(v\rightarrow u\)
  • 对于 \(i\in[l,r]\),建边 \(v\rightarrow i\)
  • 对于 \(i\in[l,r]\),建边 \(i\rightarrow v\)

求最终图的最短路。

满足 \(1\leq n\leq10^5\)

线段树优化建图

朴素建图会产生至多 \(\mathcal O(qn)\) 条边,这是无法接受的。

区间操作,考虑使用线段树如何去优化这个过程。

例如,\(n=4\),对于 \(i\in[1,3]\),建边 \(4\rightarrow i\)

如果有一个虚拟节点 \([1,2]\)\(1,2\) 均连了权值为 \(0\) 的边,那么等价于建边 \(4\rightarrow[1,2],4\rightarrow3\)

010

这是一棵维护 \(x\rightarrow[l,r]\) 的线段树,同样还有一棵维护 \(x\leftarrow[l,r]\) 的线段树。

这样,单次操作至多增加 \(\mathcal O(\log n)\) 条边,复杂度可以接受。


网络上有很多两棵线段树间连边的图,然而这样是完全没必要的。钦定线段树叶节点对应原图对应节点即可。

这样,只需要 \(\mathcal O(3n)\) 个节点和 \(\mathcal O(q\log n)\) 条边,就可以解决原问题。


注意「线段树优化建图」中的线段树不需要维护除对应原图节点、区间端点编号外的任何信息,仅仅是为了建图。

例题 AC 代码

//#include<bits/stdc++.h>
#include<algorithm>
#include<iostream>
#include<cstring>
#include<iomanip>
#include<cstdio>
#include<string>
#include<vector>
#include<cmath>
#include<ctime>
#include<deque>
#include<queue>
#include<stack>
#include<list>
#include<set>
using namespace std;
typedef long long ll;
constexpr const int N=1e5;
constexpr const ll inf=0x3f3f3f3f3f3f3f3f;
int n,cnt;
vector<pair<int,ll> >g[N<<3|1];
struct segTree{bool mode;struct node{int l,r;int id;//图上编号}t[N<<2|1];void build0(int p,int l,int r){t[p]={l,r};if(l==r){t[p].id=l;return;}t[p].id=++cnt;int mid=l+r>>1;build0(p<<1,l,mid);build0(p<<1|1,mid+1,r);if(!mode){g[t[p].id].push_back({t[p<<1].id,0});g[t[p].id].push_back({t[p<<1|1].id,0});}else{g[t[p<<1].id].push_back({t[p].id,0});g[t[p<<1|1].id].push_back({t[p].id,0});}}void build(int l,int r,bool Mode){mode=Mode;build0(1,l,r);}//mode=0:x -> [l,r]//mode=1:x <- [l,r]void create(int p,int l,int r,int x,int w){if(l<=t[p].l&&t[p].r<=r){if(!mode){g[x].push_back({t[p].id,w});}else{g[t[p].id].push_back({x,w});}return;}if(l<=t[p<<1].r){create(p<<1,l,r,x,w);}if(t[p<<1|1].l<=r){create(p<<1|1,l,r,x,w);}}
}A,B;
ll dis[N<<3|1];
void Dijkstra(int s){priority_queue<pair<ll,int>,vector<pair<ll,int> >,greater<pair<ll,int> > >q;memset(dis,0x3f,sizeof(dis));static bool vis[N<<3|1];memset(vis,0,sizeof(vis));dis[s]=0; q.push({dis[s],s});while(q.size()){int x=q.top().second;q.pop();if(vis[x]){continue;}vis[x]=true;for(auto &i:g[x]){int &v=i.first;ll &w=i.second;if(vis[v]){continue;}if(dis[x]+w<dis[v]){dis[v]=dis[x]+w;q.push({dis[v],v});}}}
}
int main(){/*freopen("test.in","r",stdin);freopen("test.out","w",stdout);*/ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);int q,s;cin>>n>>q>>s;cnt=n;A.build(1,n,0);B.build(1,n,1);while(q--){int op,u,v,l,r,w;cin>>op>>v;switch(op){case 1:cin>>u>>w;g[v].push_back({u,w});break;case 2:cin>>l>>r>>w;A.create(1,l,r,v,w);break;case 3:cin>>l>>r>>w;B.create(1,l,r,v,w);break;}}Dijkstra(s);for(int i=1;i<=n;i++){if(dis[i]==inf){cout<<"-1 ";}else{cout<<dis[i]<<' ';}}cout.flush();/*fclose(stdin);fclose(stdout);*/return 0;
}
http://www.aitangshan.cn/news/963.html

相关文章:

  • Docker生成容器时使用GPU资源异常:could not select device driver ““ with capabilities: [[gpu]]
  • logrotate日志切割详解
  • 双栈维护滑动窗口的 trick
  • 目前组合数学我学过的
  • nim语言的fmt
  • nim语言获取windows用户名
  • 微雪电子发布工业级ESP32-S3-POE工控板:8路隔离IO,双核240MHz赋能AIoT,一根网线解决供电与通信,工业物联网迎来高性价比控制新选择 - 实践
  • DelegatingHandler
  • 8月12日随笔
  • ORACLE --修改表操作 - Yu
  • SpringCloud OpenFeign
  • # 自控红绿灯-最简
  • 服务业推行目标绩效制度的 Tita 解决方案
  • 8月12日
  • MSE Nacos Controller:为 Kubernetes 生态构建配置管理与服务发现的桥梁
  • MySQL - 存储引擎之InooDB后台线程
  • 第十八天
  • HFSS许可证管理软件推荐
  • SSL自动续签
  • CodeBuddyIDE国际版体验(8月12日)
  • GAS_Aura-The Player State
  • 低空空管系统的技术融合与创新探索
  • Journalctl日志管理
  • AGC能力体验和研讨会(成都)
  • SAP 销售订单BAPI数量没写进去的原因
  • centos配置yum源与安装基础软件
  • 技术人日常避坑手册:高效工作,少踩坑 - IT
  • 平均负载详解
  • OOM Killer
  • 爬取B站视频