有一种最短路问题,有的边是从区间到区间的,这个时候点操作就不是很好办(边比较多)。于是考虑建线段树优化建图。
两颗线段树:入与出。(出表示从这里出发,入表示进到了这个点)
于是每条区间加边就可以转为log级别。
1、平行节点间,从入连向出一条0边(进入了这个点,当然可以从这个点出发)。
2、入线段树中,每个点都像左右儿子区间连0边(进入了这个区间,也可以认为进入了区间的子集)。
3、出线段树每个点都像父亲连0边(从这个区间可以出发,也可以从这个区间的父区间出发。这里要注意,到了3~5这个区间并不代表可以下一步走3发的边。)
4、每条题目给的边都从出连向入。
cf787d:
#include
#include
#include
#include
#define N 200010
using namespace std;
typedef long long ll;
const ll inf = 200000000000000ll;
struct segt {int ls, rs;}t[N<<2];
struct edge {int fr, to, val, next;}e[N*20];
int n, m, s, segcnt = 0, head[N<<2], cnt = 0, belong[N];
inline void ins(int x, int y, int z) {e[++cnt].to = y; e[cnt].fr = x; e[cnt].val = z; e[cnt].next = head[x]; head[x] = cnt;}
void build(int p, int l, int r) {
if(l == r) {belong[l] = p; return ;}
int mid = (l + r)>>1, now = p;
build((t[now].ls = ++segcnt), l, mid);
build((t[now].rs = ++segcnt), mid + 1, r);
ins(now, t[now].ls, 0); ins(now, t[now].rs, 0);
}
int sta[N<<2][2], stp[2];
void Find(int p, int l, int r, int x, int y, int k) {
if(x <= l && r <= y) {sta[++stp[k]][k] = p; return ;}
int mid = (l + r)>>1;
if(x <= mid) Find(t[p].ls, l, mid, x, y, k);
if(mid + 1 <= y) Find(t[p].rs, mid + 1, r, x, y, k);
}
ll dis[N<<2]; int v[N<<2]; deque Q;
inline void spfa() {
s = belong[s] - segcnt;
for(int i = 0; i < N<<2; ++i) dis[i] = inf; dis[s] = 0;
memset(v, 0, sizeof(v)); Q.push_back(s); v[s] = 1;
while(!Q.empty()) {
int now = Q.front(); Q.pop_front(); v[now] = 0;
for(int i = head[now]; i; i = e[i].next)
if(dis[e[i].to] > dis[now] + e[i].val) {
dis[e[i].to] = dis[now] + e[i].val;
if(!v[e[i].to]) {
v[e[i].to] = 1;
if(dis[e[i].to] < dis[(!Q.empty())?Q.front():0]) Q.push_front(e[i].to);
else Q.push_back(e[i].to);
}
}
}
}
int main() {
scanf("%d%d%d", &n, &m, &s);
build(++segcnt, 1, n);
int temp = cnt;
for(int i = 1; i <= temp; ++i) ins(e[i].to + segcnt, e[i].fr + segcnt, 0);
for(int i = 1; i <= segcnt; ++i) ins(i, i + segcnt, 0);
for(int i = 1; i <= n; ++i) belong[i]+= segcnt;
for(int i = 1; i <= m; ++i) {
int opt, v, l, r, w; scanf("%d%d%d", &opt, &v, &l);
if(opt != 1) scanf("%d", &r); else r = l; scanf("%d", &w);
stp[0] = stp[1] = 0; if(opt != 3) {Find(1, 1, n, v, v, 0); Find(1, 1, n, l, r, 1);} else {Find(1, 1, n, l, r, 0); Find(1, 1, n, v, v, 1);}
for(int i1 = 1; i1 <= stp[0]; ++i1)
for(int i2 = 1; i2 <= stp[1]; ++i2) ins(sta[i1][0] + segcnt, sta[i2][1], w);
}
spfa();
for(int i = 1; i <= n; ++i) if(dis[belong[i]] == inf) printf("-1 "); else printf("%I64d ", dis[belong[i]]);
return 0;
}