一.题目
二.题解
如果这道题目没有后面两个操作,那么就是一个Dijkstra跑过,但是当加上后两个操作,如果
v
v
v向每个区间内的点连一条边将会连
n
2
n^2
n2条边,存不下也跑不过。
这时就得使用线段树来优化Dijkstra。
我们不如直接将点
v
v
v连到区间
l
−
r
l-r
l−r上或将区间
l
−
r
l-r
l−r连到点
v
v
v上,具体操作下面我将线段树的打法解释一下:
首先要建两颗线段树 t r e e i n [ I n d e x ] , t r e e o u t [ I n d e x ] treein[Index],treeout[Index] treein[Index],treeout[Index]分别代表外面的点连到区间和区间连向外部的点,建树的时候在每棵树内建边, t r e e i n [ I n d e x ] treein[Index] treein[Index]这棵树就是从父亲向儿子连边而 t r e e o u t [ I n d e x ] treeout[Index] treeout[Index]这棵树就是儿子向父亲连边,然后每次更新,就直接将点连到完全被 l − r l-r l−r包含在内的线段树区间内,或反着连,线段树每个区间的编号从 n + 1 n + 1 n+1开始,注意跑Dijkstra时要将线段树的所有区间带着一起跑。注意不要炸空间
三.Code
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <queue>
#include <vector>
#include <cstdlib>
using namespace std;
#define M 100005
#define LL long long
const LL INF = 1e15;
struct node {
int v; LL Dis;
node (){};
node (int V, LL DIS){
v = V;
Dis = DIS;
}
bool operator < (const node& rhs) const{
return rhs.Dis < Dis;
}
};
int n, q, s, treein[M * 4], treeout[M * 4], cnt;
LL dis[M];
vector <pair <int, LL> > G[M * 8];
priority_queue <node> Q;
void build (int Index, int l, int r){
if (l == r){
treein[Index] = treeout[Index] = l;
return ;
}
int mid = l + r >> 1;
build (Index << 1, l, mid);
build ((Index << 1) | 1, mid + 1, r);
treein[Index] = ++ cnt;
treeout[Index] = ++ cnt;
G[treein[Index]].push_back (make_pair (treein[Index * 2], 0));
G[treein[Index]].push_back (make_pair (treein[Index * 2 + 1], 0));
G[treeout[Index * 2]].push_back (make_pair (treeout[Index], 0));
G[treeout[Index * 2 + 1]].push_back (make_pair (treeout[Index], 0));
}
void updatein (int Index, int l, int r, int L, int R, int from, LL val){
if (L <= l && R >= r){
G[from].push_back (make_pair (treein[Index], val));
return ;
}
int mid = (l + r) >> 1;
if (L <= mid)
updatein (Index * 2, l, mid, L, R, from, val);
if (R > mid)
updatein (Index * 2 + 1, mid + 1, r, L, R, from, val);
}
void updateout (int Index, int l, int r, int L, int R, int from, LL val){
if (L <= l && R >= r){
G[treeout[Index]].push_back (make_pair (from, val));
return ;
}
int mid = l + r >> 1;
if (L <= mid)
updateout (Index * 2, l, mid, L, R, from, val);
if (R > mid)
updateout (Index * 2 + 1, mid + 1, r, L, R, from, val);
}
void Dijkstra (){
for (int i = 1; i <= cnt; i ++)
dis[i] = INF;
dis[s] = 0;
Q.push (node (s, 0));
while (! Q.empty ()){
node now = Q.top ();
Q.pop ();
if (now.Dis != dis[now.v])
continue;
for (int i = 0; i < G[now.v].size(); i ++){
int tmp = G[now.v][i].first; LL tot = G[now.v][i].second;
if (dis[tmp] > now.Dis + tot){
dis[tmp] = now.Dis + tot;
Q.push (node (tmp, dis[tmp]));
}
}
}
}
int main (){
scanf ("%d %d %d", &n, &q, &s);
cnt = n;
build (1, 1, n);
while (q --){
int flag, v, l, r; LL w;
scanf ("%d", &flag);
if (flag == 1){
scanf ("%d %d %lld", &v, &l, &w);
G[v].push_back (make_pair (l, w));
}
if (flag == 2){
scanf ("%d %d %d %lld", &v, &l, &r, &w);
updatein (1, 1, n, l, r, v, w);
}
if (flag == 3){
scanf ("%d %d %d %lld", &v, &l, &r, &w);
updateout (1, 1, n, l, r, v, w);
}
}
Dijkstra ();
for (int i = 1; i <= n; i ++){
if (dis[i] == INF)
printf ("-1 ");
else
printf ("%lld ", dis[i]);
}
return 0;
}