1. 程式人生 > >786B Legacy(線段樹 +最短路+思維好題)

786B Legacy(線段樹 +最短路+思維好題)

Legacy(傳送門

題意

給定n顆行星,q次處理,地球位置為s,求解在q次處理後,地球到每一顆行星的位置。

其中q有三種不同的操作:

  1. 輸入v,u,w,構建一條從vu的代價為w的路線

  2. 輸入u,l,r,w,構建一條從u到區間[l,r]中任意一顆行星的代價為w的路線

  3. 輸入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; }