线段树优化建图
更新日志
2025/01/05:开工。
概念
利用线段树优化建图。
一般情况下,会出现点和区间或区间和区间连边的情况,就可以考虑线段树优化建图了。
思路
开两棵线段树,一棵储存入边,一棵储存出边。每个节点都代表对应的区间。
入树中每个点都指向其子节点,出树中相反。
区间连边时,在对应线段树中找到对应的区间点,直接连过去即可。
同时,两棵树的叶子节点也要两两连边,因为它们是相同的节点。从入树连向出树即可。
具体要求视题而定,并且方案很多。比如跑最短路,如果从入树开始跑,那么最后统计入树出树都没有问题;从出树开始跑,要么统计出树,要么特判起始点;或者直接在两个叶子之间连双向边。方法很多。
开始时应该在出树的叶子节点开始,当然在入树中显然无影响。
细节
考虑后续为图论操作,所以不封装比较好。
一个好的建议是动态开点,也方便图中节点编号。
例题
就是模板题。
代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef __int128 i128;
typedef double db;
typedef long double ld;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;
typedef pair<int,ll> pil;
typedef pair<ll,int> pli;
template <typename Type>
using vec=vector<Type>;
template <typename Type>
using grheap=priority_queue<Type>;
template <typename Type>
using lrheap=priority_queue<Type,vector<Type>,greater<Type> >;
#define fir first
#define sec second
#define pub push_back
#define pob pop_back
#define puf push_front
#define pof pop_front
#define chmax(a,b) a=max(a,b)
#define chmin(a,b) a=min(a,b)
#define rep(i,x,y) for(int i=x;i<=y;i++)
#define per(i,x,y) for(int i=x;i>=y;i--)
const int inf=0x3f3f3f3f;
const ll INF=0x3f3f3f3f3f3f3f3f;
const int mod=998244353;
const int NN=1e5+5;
const int N=4e5,M=1e5*2*2+1e5+16*2*1e5+5;
int cnt;
int hd[N],ne[M],to[M];ll ed[M];
void adde(int a,int b,ll c){
to[++cnt]=b;
ne[cnt]=hd[a];
hd[a]=cnt;
ed[cnt]=c;
}
int n;
int id[NN][2];
int lson[N],rson[N];
void build(int &x,int l,int r,int kd){
x=++n;
if(l==r){
id[l][kd]=x;
return;
}
int m=l+r>>1;
build(lson[x],l,m,kd);
build(rson[x],m+1,r,kd);
if(!kd)adde(x,lson[x],0),adde(x,rson[x],0);
else adde(lson[x],x,0),adde(rson[x],x,0);
}
void add(int lq,int rq,int y,int v,int x,int l,int r,int kd){
if(lq<=l&&r<=rq){
if(!kd)adde(y,x,v);
else adde(x,y,v);
return;
}
int m=l+r>>1;
if(lq<=m)add(lq,rq,y,v,lson[x],l,m,kd);
if(m<rq)add(lq,rq,y,v,rson[x],m+1,r,kd);
}
int nn,q,s;
int rt[2];
ll dis[N];
lrheap<pli> pq;
void dij(int be){
rep(i,1,n)dis[i]=INF;
dis[be]=0;
pq.push({0,be});
while(!pq.empty()){
auto tp=pq.top();pq.pop();
int now=tp.sec;
if(tp.fir>dis[now])continue;
for(int e=hd[now];e;e=ne[e]){
int nxt=to[e];
if(dis[nxt]>dis[now]+ed[e]){
dis[nxt]=dis[now]+ed[e];
pq.push({dis[nxt],nxt});
}
}
}
}
int main(){
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
cin>>nn>>q>>s;
build(rt[0],1,nn,0);
build(rt[1],1,nn,1);
rep(i,1,nn)adde(id[i][0],id[i][1],0);
rep(i,1,q){
int a,b,c,d,e;
cin>>e;
if(e==1){
cin>>a>>b>>d;
adde(id[a][1],id[b][0],d);
}else{
cin>>a>>b>>c>>d;
if(e==2)add(b,c,id[a][1],d,rt[0],1,nn,0);
else add(b,c,id[a][0],d,rt[1],1,nn,1);
}
}
dij(id[s][1]);
rep(i,1,nn){
if(dis[id[i][1]]<INF)cout<<dis[id[i][1]]<<" ";
else cout<<"-1 ";
}
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】