看到了大佬的做法,才发现竟然可以这样写,看起来挺复杂的,其实是个线段树建图,再用Dijkstra的过程
大佬链接
建立一个线段树a,这个线段树使所有的父节点都指着子节点(单向),权值为0。
再建立一个线段树b,这个线段树使所有的子节点都指着子父点,权值为0。
并且,a树的每个子节点都指着b树相对的子节点,且权值依然为0。
第一个是v到u,那么就是b树的v节点指向b树的u节点。
第二个是v到,L到R每一个。那么就是b树的节点v,存一条路径,可以到a树的L到R区间。(点到区间)
第三个是L到R每一个,到v。那么就是b树的L到R区间,指向a树的v节点。(区间到点)
记住,这里的所有特征就是都是从b树(向上指的那棵树出发)
最后再用所得到的图,进行Dijkstra算法。
#include<bits/stdc++.h>
#define ll long long
#define pli pair<ll,int>
#define lson k<<1,l,mid
#define rson k<<1|1,mid+1,r
using namespace std;
const int MX=1e5+9;
const ll inf=1e10+9;
int n,m,st,cnt=0,pa[MX],pb[MX],vis[MX<<3];
ll dis[MX<<3];
struct node{
int l,r,num;
}a[MX<<2],b[MX<<2];
struct Node{
int to;
ll w;
};
vector<Node> vec[MX<<3];
void builda(int k,int l,int r){
a[k].l=l,a[k].r=r,a[k].num=++cnt;
if( l==r ){
pa[l]=a[k].num;
vec[pa[l]].push_back({pb[l],0});
return ;
}
int mid=(l+r)>>1;
builda(lson);
builda(rson);
vec[a[k].num].push_back({a[k<<1].num,0});
vec[a[k].num].push_back({a[k<<1|1].num,0});
}
void buildb(int k,int l,int r){
b[k].l=l,b[k].r=r,b[k].num=++cnt;
if( l==r ){
pb[l]=b[k].num;
return ;
}
int mid=(l+r)>>1;
buildb(lson);
buildb(rson);
vec[b[k<<1].num].push_back({b[k].num,0});
vec[b[k<<1|1].num].push_back({b[k].num,0});
}
void updatea(int k,int l,int r,int L,int R,int num,ll w){
if( L<=l && r<=R ){
vec[num].push_back({a[k].num,w});
return ;
}
int mid=(l+r)>>1;
if( L<=mid )
updatea(lson,L,R,num,w);
if( mid<R )
updatea(rson,L,R,num,w);
}
void updateb(int k,int l,int r,int L,int R,int num,ll w){
if( L<=l && r<=R ){
vec[b[k].num].push_back({num,w});
return ;
}
int mid=(l+r)>>1;
if( L<=mid )
updateb(lson,L,R,num,w);
if( mid<R )
updateb(rson,L,R,num,w);
}
void dij(){
memset(vis,0,sizeof(vis));
priority_queue<pli,vector<pli>,greater<pli> > que;
for( int i=1 ; i<=cnt ; i++ )
dis[i]=inf;
dis[pa[st]]=0;
que.push({0,pa[st]});
while( !que.empty() ){
ll w=que.top().first;
int u=que.top().second;
que.pop();
vis[u]=1;
for( int i=0 ; i<vec[u].size() ; i++ ){
int v=vec[u][i].to;
ll val=vec[u][i].w;
if( vis[v]==1 )
continue;
if( dis[v]>dis[u]+val ){
dis[v]=dis[u]+val;
que.push({dis[v],v});
}
}
}
for( int i=1 ; i<=n ; i++ ){
ll ans=dis[pa[i]]==inf?-1:dis[pa[i]];
printf("%lld%c",ans,i==n?'\n':' ');
}
return ;
}
int main()
{
freopen("input.txt","r",stdin);
scanf("%d %d %d",&n,&m,&st);
buildb(1,1,n);
builda(1,1,n);
while( m-- ){
int order,u,v,l,r;
ll w;
scanf("%d",&order);
if( order==1 ){
scanf("%d %d %lld",&u,&v,&w);
vec[pb[u]].push_back({pa[v],w}); // b节点到a节点
}
else if( order==2 ){
scanf("%d %d %d %lld",&v,&l,&r,&w);
updatea(1,1,n,l,r,pb[v],w); // b节点到a的lr范围
}
else{
scanf("%d %d %d %lld",&v,&l,&r,&w);
updateb(1,1,n,l,r,pa[v],w); // b的lr范围到a节点
}
}
dij();
return 0;
}