NOI2018归程

mac2022-06-30  78

Problem

传送门

给一张图,每条边有两个参数:\(w,h\),分别代表边长与海拔

有Q个询问,每次询问从给定点出发,借助一辆只能走海拔大于h的边的车后,到一号点最短步行的距离。

Solution

正解是\(kruskal\)重构树,很好理解,也很好打,网上题解很多,这里就不讲了

下面我们讲一下一个需吸氧且随缘\(T\)点的做法

可持久化并查集

有没有感觉十分高端大气上档次?

表示没有

之前上网看过这中算法,但是一直没有看懂

问右边大佬这个是怎么实现的

结果

右边大佬:啊?……不就是可持久化那样搞一下……按质合并……就可以了吗?

\(caiji\)表示听不懂……

后来跑到隔壁的时候\(Na_2S_2O_3\ zbr\)提了一嘴

\(Na_2S_2O_3\):你别\(fake\)

\(caiji\):我是真不会

\(zbr\):啊?就是拿个可持久化数组维护一下并查集就可以了啊

\(caiji\):可持久化数组是什么?

\(Na_2S_2O_3\):就是用主席树维护一个数组啊……

(恍然大雾.jpg)

咳咳,跑题了。

现在来讲一讲这道题

先考虑离线,就是先跑一边最短路

询问与边都按从大到小排序,然后每次询问倒序进去的时候按比海拔高的约束加入能开车的边,

这个东西可以用并查集维护。

每次维护这个联通块中到一号点的最小距离,直接输出就好了。

接下来就是在线了

某位伟大的博士曾说过

勇矢博士:所有可离线做的问题都可以用可持久化数据结构在线做。

好像很有道理……

所以我们这道题可以用可持久化并查集……

对于每个询问,我们只需回到没有添加海拔比\(q\)小的路的版本,再查询\(v\)所在的联通块即可

复杂度\(O(n(logn)^2)\)

卡卡常,好像能过个鬼

拷了个海波的快输还是T了两点

Code

#include<bits/stdc++.h> #define mp make_pair #define fst first #define snd second #define LL long long #define pli pair<LL,int> #define pii pair<int,int> using namespace std; inline int read(){ int res = 0, fl = 1; char r = getchar(); for (; !isdigit(r); r = getchar()) if(r == '-') fl = -1; for (; isdigit(r); r = getchar()) res = (res << 3) + (res << 1) + r - 48; return res * fl; } char _obuf[1 << 20], _stk[20]; class Ostream { char *opos, *oend, *stkpos; public : Ostream() { oend = (opos = _obuf) + (1 << 20); stkpos = _stk; } ~Ostream() { fwrite(_obuf, 1, opos - _obuf, stdout); } void Putchar(char ch) { *opos++ = ch; if(opos == oend) { fwrite(_obuf, 1, 1 << 20, stdout); opos = _obuf; } } Ostream& operator<<(int n) { do { *++stkpos = n % 10 ^ 48; n /= 10; } while(n); while(stkpos != _stk) Putchar(*stkpos--); return *this; } Ostream& operator<<(char c) { Putchar(c); return *this; } Ostream& operator<<(const char* str) { while(*str != '\0') Putchar(*str++); return *this; } } out; inline void chkmin(int &A, int &B) { A = min(A, B);} inline void chkmax(int &A, int &B) { A = max(A, B);} const int Maxm = 4e5 + 10, Maxn = 2e5 + 10; vector <pii> g[Maxn]; struct node{ int u, v, h; bool operator < (const node A) const{ return h > A.h;} }Map[Maxm]; int n, m, Q, K, S, ans; int root[Maxn], dis[Maxn]; namespace CMT{ #define mid ((l + r) >> 1) int ls[Maxn << 6], rs[Maxn << 6], cnt, root[Maxm << 2], Tim; struct TRE{ int fa, siz, dis; }tre[Maxn << 6]; inline void build(int &rt, int l, int r){ rt = ++cnt; if(l == r) {tre[rt].fa = l, tre[rt].siz = 1, tre[rt].dis = dis[l]; return;} build(ls[rt], l, mid); build(rs[rt], mid + 1, r); } inline void Init(){ cnt = 0; build(root[1], 1, n); Tim = 0;} inline int Query(int Begin, int rt, int l, int r, int pos){ if(l == r){return tre[rt].fa == l ? rt : Query(Begin, Begin, 1, n, tre[rt].fa);} if(mid >= pos) return Query(Begin, ls[rt], l, mid, pos); else return Query(Begin, rs[rt], mid + 1, r, pos); } inline void Modify_fa(int grt, int &rt, int l, int r, int pos, int fa){ rt = ++cnt, ls[rt] = ls[grt], rs[rt] = rs[grt], tre[rt] = tre[grt]; if(l == r) { tre[rt].fa = fa; return;} if(mid >= pos) Modify_fa(ls[grt], ls[rt], l, mid, pos, fa); else Modify_fa(rs[grt], rs[rt], mid + 1, r, pos, fa); } inline void Modify(int grt, int &rt, int l, int r, int pos, int siz, int Dis){ rt = ++cnt, ls[rt] = ls[grt], rs[rt] = rs[grt], tre[rt] = tre[grt]; if(l == r){ tre[rt].siz += siz, chkmin(tre[rt].dis, Dis); return; } if(mid >= pos) Modify(ls[grt], ls[rt], l, mid, pos, siz, Dis); else Modify(rs[grt], rs[rt], mid + 1, r, pos, siz, Dis); } inline int link(int u, int v){ register int rfu = Query(root[Tim << 1 | 1], root[Tim << 1 | 1], 1, n, u); register int rfv = Query(root[Tim << 1 | 1], root[Tim << 1 | 1], 1, n, v); if(tre[rfu].fa == tre[rfv].fa) return 0; Tim++; if(tre[rfu].siz > tre[rfv].siz) swap(rfu, rfv); Modify_fa(root[(Tim << 1) - 1], root[Tim << 1], 1, n, tre[rfu].fa, tre[rfv].fa); Modify(root[Tim << 1], root[Tim << 1 | 1], 1, n, tre[rfv].fa, tre[rfu].siz, tre[rfu].dis); return Tim << 1 | 1; } inline LL Query_dis(int Time, int v){ return tre[Query(root[Time], root[Time], 1, n, v)].dis; } #undef mid } bitset<Maxn> vis, clean; inline void dijstra(){ priority_queue <pii> Q; memset(dis, 0x3f, sizeof dis); vis = clean; Q.push(mp(0, 1)); dis[1] = 0; while(!Q.empty()){ register int now = Q.top().snd; Q.pop(); if(vis[now]) continue; vis[now] = 1; for (register int i = g[now].size() - 1; i >= 0; --i){ register int nxt = g[now][i].fst; if(dis[nxt] > dis[now] + g[now][i].snd) dis[nxt] = dis[now] + g[now][i].snd, Q.push(mp(-dis[nxt], nxt)); } } } set<pii> Tim; inline void work(int &T){ n = read(), m = read(), ans = 0; for (register int i = 1; i <= m; ++i){ register int u = read(), v = read(), w = read(), h = read(); Map[i] = (node){u, v, h}; g[u].push_back(mp(v, w)); g[v].push_back(mp(u, w)); } dijstra(); sort(Map + 1, Map + 1 + m); CMT::Init(); for (register int i = 1; i <= m; ++i){ register int u = Map[i].u, v = Map[i].v; register int TIME = CMT::link(u, v); if(TIME) Tim.insert(mp(Map[i].h, -TIME)); } Q = read(), K = read(), S = read(); Tim.insert(mp(S + 1, -1)); Tim.insert(mp(0, -(CMT::Tim << 1 | 1))); while(Q--){ register int v = ((LL)read() + K * ans - 1) % n + 1; register int p = ((LL)read() + K * ans) % (S + 1); pii Time = *Tim.upper_bound(mp(p, 1e9)); ans = CMT::Query_dis(-Time.snd, v); out << ans << '\n'; } if(T) Tim.clear(); if(T) for (register int i = 1; i <= n; ++i) g[i].clear(); } int main(){ freopen("a.in","r",stdin); freopen("a.out","w",stdout); int T = read(); while(T--) work(T); return 0; }

转载于:https://www.cnblogs.com/LZYcaiji/p/10622087.html

最新回复(0)