【NOI2018】歸程
阿新 • • 發佈:2018-07-22
每一個 temp getch pre clear getc realm 計算 ons
【NOI2018】歸程
題目描述
本題的故事發生在魔力之都,在這裏我們將為你介紹一些必要的設定. 魔力之都可以抽象成一個 >\(1\) 個節點、 \(m\) 條邊的無向連通圖(節點的編號從 \(1\) 至 \(n\) )。我們依次用 \(l, a\) 描述一
條邊的長度、海拔。 作為季風氣候的代表城市,魔力之都時常有雨水相伴,因此道路積水總是不
可避免 的。由於整個城市的排水系統連通,因此有積水的邊一定是海拔相對最低的一些邊。我們用水>位線來描述降雨的程度,它的意義是:所有海拔不超過水位線的邊都是有積水的。Yazid 是一名來自魔力之都的\(OIer\),剛參加完\(ION2018\)
的他將踏上歸程,回到他 溫暖的家。 Yazid 的家恰好在魔力之都的 \(1\) 號節點。對於接下來 \(Q\) 天,每一天Yazid 都會告訴你他的出發點 \(v\) ,以及當天的水位線 \(p\) 。 每一天,Yazid 在出發點都擁有一輛車。這輛車由於一些故障不能經過有積水的邊。 Yazid 可以在任意節點下車,這樣接下來他就可以步行經過有積水的邊。但車會被留在他下車的節點並不會再被使用。 需要特殊說明的是,第二天車會被重置,這意味著:車會在新的出發點被準備好。Yazid 不能利用之前在某處停放的車。Yazid 非常討厭在雨天步行,因此他希望在完成回家這一目標的同時,最小化他步行經過的邊的總長度。請你幫助 Yazid 進行計算。 本題的部分測試點強制在線。
解題思路 :
觀察發現,對於詢問點能通過沒有水的邊能到達的點 \(u\),在此下車的答案就是 \(1\) 到它的最短路 \(dis_u\).
此時有一個很顯然的離線做法,將詢問的 \(p\) 從大到小排序,依次加邊維護沒有水的邊的聯通塊,並維護每一個塊的 \(dis\) 最小值即可
考慮強制在線就是把並查集可持久化,於是大力碼一棵主席樹即可以 \(O(nlog^2n)\) 的復雜度解決此題.
考慮到要可持久化的數組比較多,常數有點大,可以把聯通塊的 \(Mindis\) 以取反的形式存在 \(fa[rt]\) 上,可以少可持久化一個數組.
#include<bits/stdc++.h> #define inf (0x7f7f7f7f) #define Max(a, b) ((a) > (b) ? (a) : (b)) #define Min(a, b) ((a) < (b) ? (a) : (b)) typedef long long ll; using namespace std; template <class T> inline void read(T &x){ int f = 0, ch = 0; x = 0; for(; !isdigit(ch); ch = getchar()) if(ch == ‘-‘) f = 1; for(; isdigit(ch); ch = getchar()) x = x * 10 + ch - 48; if(f) x = -x; } const int N = 700005, M = 1200005; int n, m, Q, K, S; int a[M], b[M], nxt[M], head[N], dis[N], cnt; struct Node{ ll d, id; bool operator < (const Node &A) const{ return d > A.d; } }; priority_queue<Node> pq; inline void add(int x, int y, int z){ a[++cnt] = y, b[cnt] = z, nxt[cnt] = head[x], head[x] = cnt; } inline void dijkstra(){ for(int i = 1; i <= n; i++) dis[i] = inf / 3; dis[1] = 0, pq.push((Node){0, 1}); while(!pq.empty()){ Node now = pq.top(); pq.pop(); int val = now.d, u = now.id; if(dis[u] < val) continue; for(int p = head[u]; p; p = nxt[p]){ int v = a[p]; if(dis[u] + b[p] < dis[v]){ dis[v] = dis[u] + b[p]; pq.push((Node){dis[v], v}); } } } } struct PersistableArray{ int rt[N], s[M*25], lc[M*25], rc[M*25], size; inline void clear(){ for(int i = 1; i <= size; i++) lc[i] = rc[i] = s[i] = 0; for(int i = 1; i <= n; i++) rt[i] = 0; size = 0; } inline void build(int &u, int l, int r, int *a){ u = ++size; if(l == r) return (void) (s[u] = a[l]); int mid = l + r >> 1; build(lc[u], l, mid, a), build(rc[u], mid + 1, r, a); } inline void Ins(int &u, int pr, int l, int r, int pos, int v){ u = ++size; if(l == r) return (void) (s[u] = v); int mid = l + r >> 1; lc[u] = lc[pr], rc[u] = rc[pr]; if(pos <= mid) Ins(lc[u], lc[pr], l, mid, pos, v); else Ins(rc[u], rc[pr], mid + 1, r, pos, v); } inline int query(int u, int l, int r, int pos){ if(l == r) return s[u]; int mid = l + r >> 1; if(pos <= mid) return query(lc[u], l, mid, pos); else return query(rc[u], mid + 1, r, pos); } inline int get(int u, int pos){ return query(rt[u], 1, n, pos); } inline void mof(int u, int pos, int v){ Ins(rt[u], rt[u], 1, n, pos, v); } }fa, sz; namespace Dsu{ int a[N], ban; inline int ask(int now, int x){ int p = fa.get(now, x); if(p <= 0) return x; else return ask(now, p); } inline void unite(int x, int y){ int p = ask(ban, x), q = ask(ban, y); if(p == q) return; int szp = sz.get(ban, p), szq = sz.get(ban, q); if(szp > szq) swap(p, q); int vap = fa.get(ban, p), vaq = fa.get(ban, q); fa.mof(ban, p, q), fa.mof(ban, q, Max(vap, vaq)); sz.mof(ban, q, szp + szq); } inline void addban(){ fa.rt[ban+1] = fa.rt[ban]; sz.rt[ban+1] = sz.rt[ban], ban++; } inline void prepare(){ ban = 0; for(int i = 1; i <= n; i++) a[i] = -dis[i]; fa.build(fa.rt[0], 1, n, a); for(int i = 1; i <= n; i++) a[i] = 1; sz.build(sz.rt[0], 1, n, a); } } int hs[N], c[N]; struct Edge{ int x, y, a; } e[M]; inline bool cmp(Edge A, Edge B){ return A.a < B.a; } inline void solve(int l, int r){ Dsu::addban(); for(int i = l; i <= r; i++) hs[i] = Dsu::ban; for(int i = l; i <= r; i++) Dsu::unite(e[i].x, e[i].y); } inline void BuildDsu(){ sort(e + 1, e + m + 1, cmp), e[0].a = e[m+1].a = -1; Dsu::prepare(); for(int i = m, r; i >= 1; i--){ if(e[i].a != e[i+1].a) r = i; if(e[i].a != e[i-1].a) solve(i, r); } hs[m+1] = 0; for(int i = 1; i <= m; i++) c[i] = e[i].a; } inline int query(int u, int p){ int pos = upper_bound(c + 1, c + m + 1, p) - c; int rt = Dsu::ask(hs[pos], u); return -fa.get(hs[pos], rt); } inline void cleartype(){ #define mem(x) memset(x, 0, sizeof(x)) fa.clear(), sz.clear(); mem(a), mem(b), mem(nxt), mem(head), cnt = 0; } inline void init(){ read(n), read(m); for(int i = 1, x, y, z, a; i <= m; i++){ read(x), read(y), read(z), read(a); add(x, y, z), add(y, x, z), e[i] = (Edge){x, y, a}; } read(Q), read(K), read(S); } inline void realmain(){ cleartype(), init(), dijkstra(), BuildDsu(); int lastans = 0; while(Q--){ int u, p; read(u), read(p); p = (p + K * lastans) % (S + 1); u = (u + K * lastans - 1) % n + 1; printf("%d\n", lastans = query(u, p)); } } int main(){ int T; read(T); while(T--) realmain(); return 0; }
【NOI2018】歸程