线段树优化建图 学习笔记&模板
E1_de5truct0r · · 个人记录
模板题 - 题面:Link
思路
如果只有
对于线段树内部,父亲向儿子连一条长度为
复杂度分析:
线段树单次查询 / 修改最多涉及
代码
#include <bits/stdc++.h>
#define cint const int
using namespace std;
cint MAXN=100005,MAXLOG=(MAXN<<1)*25;
vector<pair<int,int> > E[MAXLOG];
int dis[MAXLOG];
bool vis[MAXLOG];
int tot,num[MAXN];
struct Tree{int ls,rs;}tr[MAXLOG];
inline void add(cint &u,cint &v,cint &w){
E[u].push_back(make_pair(v,w));
}
void build(int &p,int l,int r){
if(!p) p=++tot;
if(l==r){
num[l]=p; // num[i] 意思是表示 [i,i] 区间(即 i 这个点)的线段树节点的编号
return;
}
int mid=(l+r)>>1;
build(tr[p].ls,l,mid); // 继续向下
build(tr[p].rs,mid+1,r);
add(p,tr[p].ls,0); // 父亲向儿子加边
add(p,tr[p].rs,0);
}
void update(int p,int l,int r,int st,int en,int u,int w){ // u 向 [st,en] 加长为 w 的边
if(l>en || r<st) return;
if(st<=l && r<=en){
add(u,p,w); // 被包含在 [l,r] 内的区间,对答案有贡献,加边并 return
return;
}
int mid=(l+r)>>1;
update(tr[p].ls,l,mid,st,en,u,w);
update(tr[p].rs,mid+1,r,st,en,u,w);
}
void Dijkstra(int root){ // 标准の Dijkstra
memset(dis,0x3f,sizeof(dis));
priority_queue<pair<int,int> > q;
dis[root]=0; q.push(make_pair(0,root));
while(!q.empty()){
int u=q.top().second; q.pop();
if(vis[u]) continue;
vis[u]=1;
for(int i=0;i<E[u].size();i++){
int v=E[u][i].first,w=E[u][i].second;
if(dis[v]>dis[u]+w){
dis[v]=dis[u]+w;
q.push(make_pair(-dis[v],v));
}
}
}
}
int main(){
int n,m,root=0; cin>>n>>m;
build(root,1,n);
for(int i=1;i<=m;i++){
int op,u; cin>>op>>u;
if(op==1){
int v,w; cin>>v>>w;
update(root,1,n,v,v,num[u],w);
}
else{
int l,r,w; cin>>l>>r>>w;
update(root,1,n,l,r,num[u],w);
}
}
Dijkstra(num[1]);
for(int i=1;i<=n;i++){
if(dis[num[i]]==1061109567) cout<<"-1 ";
else cout<<dis[num[i]]<<" ";
}
return 0;
}