Legacy(传送门)
题意
给定
n
颗行星,
其中 q 有三种不同的操作:
输入
v,u,w ,构建一条从 v 到u 的代价为 w 的路线输入
u,l,r,w ,构建一条从 u 到区间[l,r] 中任意一颗行星的代价为 w 的路线输入
u,l,r,w ,构建区间[l,r]中任意一颗行星到 u 的代价为w 的路线解题思路
由于涉及到区间操作,用线段树处理,主要是因为线段树处理在这道题简直是神思维。
先通过构建一颗线段树,在线段树上构建边,边的构建方法如下:
对于每一个线段树上的节点,构建一条节点到节点所管辖区域的每一个点价值为0的边,如下图然后构建一条从每一个点到包含它区间的代价为 0 的路线[此处建边有跟简单直观的,就是建立
[l,l] 到 l 的双向边,但是由于他们的代价为0 再求最短路的时候会有点问题,导致有些点不会被访问,所以只能重新建立一遍新的节点用来充当区间的出路。],这样构建的边的个数基本就是 nlogn最后求一遍最短路就可以了
代码
#include <cstdio> #include <cstring> #include <cstdlib> #include <algorithm> #include <queue> #define lson rt << 1, l, mid #define rson rt << 1 | 1, mid + 1, r #define FIN freopen("input.txt", "r", stdin) using namespace std; typedef long long LL; typedef pair<LL, LL> PLL; const LL INF = 0x3f3f3f3f3f3f3f3fLL; const int MAXN = 3e5 + 5; int n,q, s, t, qn; vector<PLL> E[MAXN << 2]; int ID[MAXN << 2], IDD[MAXN << 2]; LL d[MAXN << 2]; bool vis[MAXN << 2]; void init(){ for(int i= 0;i < MAXN;i ++){ E[i].clear(); } } void build(int rt, int l, int r, int flag){ if(flag == 0) ID[rt] = ++ qn;//给每一个节点编号 else IDD[rt] = ++ qn; for(int i = l;i <= r;i ++){ if(flag == 0) E[ID[rt]].push_back(make_pair(i, 0)); else E[i].push_back(make_pair(IDD[rt], 0)); } if(l == r) return; int mid = (l + r) >> 1; build(lson, flag); build(rson, flag); } void update(int rt, int l, int r,int u, int L, int R, int w, int flag){ if(L <= l && r <= R){ if(flag == 0){ E[u].push_back(make_pair(ID[rt], w)); } else{ E[IDD[rt]].push_back(make_pair(u, w)); } return ; } int mid = (l + r) >> 1; if(L <= mid) update(lson, u, L, R, w, flag); if(R > mid) update(rson, u, L, R, w, flag); } priority_queue<PLL, vector<PLL>, greater<PLL> > Q; int main(){ // FIN; int u, v, w, l, r; while(~scanf("%d%d%d", &n, &q, &s)){ init(); qn = n; build(1, 1, n, 0); build(1, 1, n, 1); for(int i = 0;i < q;i ++){ scanf("%d", &t); if(t == 1){ scanf("%d%d%d", &u, &v, &w); E[u].push_back(make_pair(v, w)); } else if(t == 2){//u -> [l, r] scanf("%d%d%d%d", &u, &l, &r, &w); update(1, 1, n, u, l, r, w, 0); } else if(t == 3){//[l, r] -> u; scanf("%d%d%d%d", &u, &l, &r, &w); update(1, 1, n, u, l, r, w, 1); } } memset(d, INF, sizeof(d)); memset(vis, false, sizeof(vis)); d[s] = 0; while(!Q.empty()) Q.pop(); Q.push(make_pair(0, s)); while(!Q.empty()){ PLL e = Q.top(); Q.pop(); int u = e.second; if(vis[u]) continue; vis[u] = true; for(int i = 0;i < E[u].size();i ++){ PLL &ed = E[u][i]; if(!vis[ed.first] && d[ed.first] > d[u] + ed.second){ d[ed.first] = d[u] + ed.second; Q.push(make_pair(d[ed.first], ed.first)); } } } for(int i = 1;i <= n;i ++){ printf("%lld%c", d[i] == INF ? -1 : d[i], i == n ? '\n' : ' '); } } return 0; }