戳这里啊~~~
给你三种操作:(1)点到点建边;(2)点到区间建边;(3)区间到点建边;最后求起点到其他点的最短距离
最短距离无非建边跑Dijkstra即可,考虑如何对区间建边,如果直接对区间的每一点建边,那N^2的复杂度是行不通的,考虑将区间映射到线段树上的一个点:
(1)建两颗线段树,一颗表示出度的点,一颗表示入度的点
(2)对于表示出度的树,对每一节点和它父亲节点连一条长度为0的单向边(如果能从父亲出发,那么儿子也一定能);对于表示入度的树,对每一节点和它的儿子节点连一条长度为0的单向边(如果能到达父亲,那么也一定能达到儿子),并将其叶子节点和第一颗树对应的节点连一条长度为0的单向边(相当于从到达的点又出发),完全可以只建一颗树,但这样会走很多无用的边
(3)为了能区别两颗树,就必须给两颗树从新编号,建边时,直接找到对应的编号建边即可
#include
using namespace std;
typedef long long LL;
const int maxn = 2e5+15;
const LL inf = 1e18;
inline int read() {
int x = 0, f = 1;
char c = getchar();
for (; !isdigit(c); c = getchar()) if (c == '-') f = -1;
for (; isdigit(c); c = getchar()) x = x * 10 + c - '0';
return x * f;
}
inline void write(LL x)
{
if(x<0) putchar('-'),x=-x;
if(x>9) write(x/10);
putchar(x%10+'0');
}
int n,q,s,t,l,r,w,p,u,v,tot;
int head[maxn<<3],cnt,tra[maxn<<3],trb[maxn<<3],in[maxn],out[maxn];
struct edge{
int to,nxt,w;
}e[maxn<<4];
inline void add(int u,int v,int _w){
e[++cnt].to = v;e[cnt].w = _w;
e[cnt].nxt = head[u];head[u] = cnt;
}
void build(int l,int r,int x){
tra[x]=++tot; trb[x]=++tot;
if(l == r){
out[l] = trb[x];in[l] = tra[x];
add(trb[x],tra[x],0);
return ;
}
int mid = (l+r) >> 1;
build(l,mid,x<<1);
build(mid+1,r,x<<1|1);
add(tra[x<<1],tra[x],0);
add(tra[x<<1|1],tra[x],0);
add(trb[x],trb[x<<1],0);
add(trb[x],trb[x<<1|1],0);
}
void Updata(int l,int r,int L,int R,int x,int v,int w,int op){
if(l > R || r < L) return ;
if(l >= L && r <= R){
if(op == 2) add(in[v],trb[x],w);
else add(tra[x],out[v],w);
return;
}
int mid = (l+r) >> 1;
Updata(l,mid,L,R,x<<1,v,w,op);
Updata(mid+1,r,L,R,x<<1|1,v,w,op);
}
LL dis[maxn<<3];
struct node{
int x; LL len;
friend bool operator <(node a,node b){
return a.len > b.len;
}
};
void diskstra(){
for(int i = 0;i <= tot; ++i) dis[i] = inf;
dis[in[s]] = dis[out[s]] = 0;
priority_queue q;
q.push(node{in[s],0LL});
while(!q.empty()){
node now = q.top();q.pop();
if(now.len > dis[now.x]) continue;
for(int i = head[now.x]; i ; i = e[i].nxt){
int v = e[i].to;
if(dis[v] > dis[now.x] + e[i].w){
dis[v] = dis[now.x] + e[i].w;
q.push(node{v,dis[v]});
}
}
}
}
int main(){
n = read(),q =read(),s = read();
build(1,n,1);
while(q--){
t = read();
if(t == 1){
u = read(),v = read(),w = read();
add(in[u],out[v],w);
}
else{
v = read(),l = read(),r = read(),w = read();
Updata(1,n,l,r,1,v,w,t);
}
}
diskstra();
for(int i = 1;i <= n; ++i){
if(dis[out[i]] == inf) printf("-1 ");
else write(dis[out[i]]),putchar(' ');
}
return 0;
}