题目链接
题解:
这道题太神仙了!
由于有整个区间指向点的边和点指向一整个区间的边,所以边数它爆炸了。
那么怎么样可以将边数减下来呢?这里以一个点连向一个区间的点为例子,我们可以建立一颗线段树,每个点代表一个区间,每个区间连一条边到它的各个子区间,边权为 0 ,然后将叶子节点连向各个原始的节点。那么要增加一个点连向一个区间的边就变成了这个点连向这个区间所包含的线段树中的节点即可。
同样,增加一个区间到一个点的边我们可以再建一棵线段树,只是把原来的边反过来即可。(注意不可以建在一起,因为双向边都是 0 的话最短路就一直是 0 了!)
下面这张图是第二个样例建的图:
代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
#define PI acos(-1.0)
#define INF 0x3f3f3f3f3f3f3f3f
#define P pair<ll, int>
#define debug(x) cout << #x << ": " << x << endl
#define fastio ios::sync_with_stdio(false), cin.tie(0)
const int mod = 1e9 + 7;
const int M = 1000000 + 10;
const int N = 500000 + 10;
int n, q, s, t;
vector<P> G[N];
ll d[N];
int id[2][N], cnt;
void dijkstra(int st)
{
for(int i = 1; i <= cnt; i ++) d[i] = INF; d[st] = 0;
bool vis[N] = { false };
priority_queue<P, vector<P>, greater<P>> que;
que.push(P{0, st});
while(que.size()) {
int now = que.top().second; ll dis = que.top().first;
que.pop();
if(vis[now]) continue;
vis[now] = true;
for(int i = 0; i < G[now].size(); i ++) {
if(dis + G[now][i].first < d[G[now][i].second]) {
d[G[now][i].second] = dis + G[now][i].first;
que.push(P{d[G[now][i].second], G[now][i].second});
}
}
}
}
void build(int kd, int &now, int l, int r, int rt)
{
now = ++cnt;
if(l == r) {
if(kd) G[now].push_back(P{0, l});
else G[l].push_back(P{0, now});
return ;
}
int mid = (l + r) >> 1;
build(kd, id[kd][rt << 1], l, mid, rt << 1);
build(kd, id[kd][rt << 1 | 1], mid + 1, r, rt << 1 | 1);
if(kd) {
G[now].push_back(P{0, id[kd][rt << 1]});
G[now].push_back(P{0, id[kd][rt << 1 | 1]});
} else {
G[id[kd][rt << 1]].push_back(P{0, now});
G[id[kd][rt << 1 | 1]].push_back(P{0, now});
}
}
void single(int st, int L, int R, int val, int l, int r, int rt)
{
if(L <= l && r <= R) {
G[st].push_back(P{val, id[1][rt]});
return ;
}
int mid = (l + r) >> 1;
if(L <= mid) single(st, L, R, val, l, mid, rt << 1);
if(mid < R) single(st, L, R, val, mid + 1, r, rt << 1 | 1);
}
void segment(int ed, int L, int R, int val, int l, int r, int rt)
{
if(L <= l && r <= R) {
G[id[0][rt]].push_back(P{val, ed});
return ;
}
int mid = (l + r) >> 1;
if(L <= mid) segment(ed, L, R, val, l, mid, rt << 1);
if(mid < R) segment(ed, L, R, val, mid + 1, r, rt << 1 | 1);
}
signed main()
{
scanf("%d %d %d", &n, &q, &s);
cnt = n;
build(0, id[0][1], 1, n, 1);
build(1, id[1][1], 1, n, 1);
for(int i = 1, t; i <= q; i ++) {
scanf("%d", &t);
if(t == 1) {
int u, v, w;
scanf("%d %d %d", &u, &v, &w);
G[u].push_back(P{w, v});
} else if(t == 2) {
int v, l, r, w;
scanf("%d %d %d %d", &v, &l, &r, &w);
single(v, l, r, w, 1, n, 1);
} else {
int v, l, r, w;
scanf("%d %d %d %d", &v, &l, &r, &w);
segment(v, l, r, w, 1, n, 1);
}
}
dijkstra(s);
for(int i = 1; i <= n; i ++) {
if(d[i] == INF) d[i] = -1;
printf("%lld%c", d[i], i == n ? '\n' : ' ');
}
return 0;
}
/*
Rejoicing in hope, patient in tribulation.
*/