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
#define mp make_pair
#define fst first
#define snd second
#define LL long long
#define pli pair
#define pii pair
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 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 vis, clean;
inline void dijstra(){
priority_queue 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 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;
}