有一种最短路问题,有的边是从区间到区间的,这个时候点操作就不是很好办(边比较多)。于是考虑建线段树优化建图。
两颗线段树:入与出。(出表示从这里出发,入表示进到了这个点)
于是每条区间加边就可以转为log级别。
1、平行节点间,从入连向出一条0边(进入了这个点,当然可以从这个点出发)。
2、入线段树中,每个点都像左右儿子区间连0边(进入了这个区间,也可以认为进入了区间的子集)。
3、出线段树每个点都像父亲连0边(从这个区间可以出发,也可以从这个区间的父区间出发。这里要注意,到了3~5这个区间并不代表可以下一步走3发的边。)
4、每条题目给的边都从出连向入。
cf787d:
#include <cstdio> #include <cstring> #include <algorithm> #include <deque> #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<int> 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; }