线段树优化建图
前置芝士:动态开点线段树。
先放一个板子题:Legacy。
题意放一下:
有
-
从
到 连一条权值 的有向边。 -
从
向编号在区间 内的每个点连一条边权为 的有向边。 -
从编号在区间
内的每个点向 连一条边权为 的有向边。
做完所有操作后,求 -1
。
数据范围:
说一下一些思路,首先,如果每次都暴力连边,时间复杂度为
观察到区间连边这个东西,想一想能够优化区间的东西,例如线段树之类的。
我们既然要进行区间连边,就要能够用较少的点表示出修改区间,这也是我们想到线段树的原因。
我们弄两棵线段树,一棵代表入边(称为入树),另一棵代表出边(称为出树)。在初始化中,入树的边由儿子指向父亲,出树中的边由父亲指向儿子。
我们在区间修改操作中,每一次在这个区间被待修改区间完全包含时,把这个点的节点编号向给出的节点连边,具体是谁向谁连边要看是第几个操作。
这里为了省一些空间,我们使用的是动态开点线段树。
最后跑一个简单的
到这里,基本的思路就说完了,下面放一下代码:
#include<bits/stdc++.h>
#define int long long
#define N 100005
#define M 300005
#define K 20
#define pii pair<int,int>
#define x first
#define y second
#define inf 0x3f3f3f3f3f3f3f3f
using namespace std;
int h[M],e[M*K],w[M*K],ne[M*K],idx;
int n,m,s,rt1,rt2;
int lc[M*K],rc[M*K];
int dis[M],S,cnt;
bool st[M];
void add(int a,int b,int c){//链式前向星建边
e[idx]=b;w[idx]=c;ne[idx]=h[a];h[a]=idx++;
}
void build1(int &u,int l,int r){
if(l==r){
u=l;
return;
}
u=++cnt;//经典的动态开点
int mid=l+r>>1;
build1(lc[u],l,mid);
build1(rc[u],mid+1,r);//线段树基本递归
add(u,lc[u],0);//上文提到的树内连边
add(u,rc[u],0);
}
void build2(int &u,int l,int r){//这里同上
if(l==r){
u=l;
return;
}
u=++cnt;
int mid=l+r>>1;
build2(lc[u],l,mid);
build2(rc[u],mid+1,r);
add(lc[u],u,0);
add(rc[u],u,0);
}
void modify(int u,int l,int r,int L,int R,int point,int val,int type){
if(l>=L&&r<=R){//该区间被目标区间完全包含
if(type==2)add(point,u,val);
else add(u,point,val);//根据操作连边
return;
}
int mid=l+r>>1;
if(L<=mid)modify(lc[u],l,mid,L,R,point,val,type);//线段树基本递归
if(R>mid)modify(rc[u],mid+1,r,L,R,point,val,type);
}
void dij(int S){//dijkstra板子
priority_queue<pii,vector<pii>,greater<pii>>q;
memset(dis,0x3f,sizeof dis);
memset(st,0,sizeof st);
dis[S]=0;
q.push({dis[S],S});
while(!q.empty()){
int t=q.top().y;
q.pop();
if(st[t])continue;
st[t]=1;
for(int i=h[t];~i;i=ne[i]){
int j=e[i];
if(dis[j]>dis[t]+w[i]){
dis[j]=dis[t]+w[i];
q.push({dis[j],j});
}
}
}
}
signed main(){
cin>>n>>m>>S;
cnt=n;
memset(h,-1,sizeof h);
build1(rt1,1,n);
build2(rt2,1,n);
while(m--){
int op,point,nxt,val,L,R;
cin>>op;
if(op==1){
cin>>point>>nxt>>val;//单点连边暴力连一下即可
add(point,nxt,val);
}
else{
cin>>point>>L>>R>>val;//区间连边
if(op==2)modify(rt1,1,n,L,R,point,val,op);
else modify(rt2,1,n,L,R,point,val,op);
}
}
dij(S);//跑最短路,输出答案
for(int i=1;i<=n;i++){
if(dis[i]>=inf)dis[i]=-1;
cout<<dis[i]<<' ';
}
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】