线段树优化建图板子题。
首先对于题目的三种连边方式,我们可以通过三种办法来分别维护。
点点连边直接 Addedge 即可。
点->区间 连边可以建立一棵线段树,这个线段树代表区间和普通的一样,只不过在建树的时候连接两条边权为 0 的边到左右区间即可。
区间->点 连边可以再建立一个线段树,然后这个线段树就是拿来反向连边的。
最后就是直接最短路即可。
具体实现看代码:
#include<bits/stdc++.h>
using namespace std;
template <typename T>
inline void read(T &x){
x=0;char ch=getchar();bool f=false;
while(!isdigit(ch)){if(ch=='-'){f=true;}ch=getchar();}
while(isdigit(ch)){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
x=f?-x:x;
return ;
}
template <typename T>
inline void write(T x){
if(x<0) putchar('-'),x=-x;
if(x>9) write(x/10);
putchar(x%10^48);
return ;
}
const int N=3e5+5,M=2e6+5;
#define ll long long
int n,q,s,cur,root[3];
int ls[M],rs[M];
int head[M],nex[M],to[M],idx;
ll val[M];
inline void add(int u,int v,ll w){
nex[++idx]=head[u];
to[idx]=v;
val[idx]=w;
head[u]=idx;
return ;
}
void Build(int &x,int l,int r,int type){
if(l==r) return x=l,void();
int mid=l+r>>1;x=++cur;
Build(ls[x],l,mid,type),Build(rs[x],mid+1,r,type);
if(type==2) add(x,ls[x],0),add(x,rs[x],0);
else add(ls[x],x,0),add(rs[x],x,0);
return ;
}
void Modify(int x,int l,int r,int ql,int qr,int u,ll w,int type){
if(ql<=l&&r<=qr) return type==2?add(u,x,w):add(x,u,w),void();
int mid=l+r>>1;
if(ql<=mid) Modify(ls[x],l,mid,ql,qr,u,w,type);
if(qr>mid) Modify(rs[x],mid+1,r,ql,qr,u,w,type);
return ;
}
ll dis[M];
bool vis[M];
typedef pair<ll,int> PII;
priority_queue<PII,vector<PII>,greater<PII> >que;
void Dijkstra(){
memset(dis,0x3f,sizeof(dis));
dis[s]=0;
que.push({0,s});
while(!que.empty()){
PII t=que.top();que.pop();
int x=t.second;ll dist=t.first;
if(vis[x]) continue;
vis[x]=true;
for(int i=head[x];i;i=nex[i]){
int y=to[i];
if(dis[y]>dist+val[i]){
dis[y]=dist+val[i];
que.push({dis[y],y});
}
}
}
return ;
}
signed main(){
read(n),read(q),read(s);cur=n;
Build(root[1],1,n,2);Build(root[2],1,n,3);
for(int i=1;i<=q;i++){
int op,l,r,u,v;ll w;
read(op);
if(op==1) read(u),read(v),read(w),add(u,v,w);
else read(u),read(l),read(r),read(w),Modify(root[op-1],1,n,l,r,u,w,op);
}
Dijkstra();
for(int i=1;i<=n;i++) write(dis[i]==dis[(M)-100]?-1:dis[i]),putchar(' ');
return 0;
}