P4768 [NOI2018] 归程
作者:互联网
题目大意
\(n(n\le2\cdot10^5)\) 个点, \(m(m\le4\cdot10^5)\) 条边的无向图,每条边有长度 \(l(l\le10^4)\) ,海拔 \(a(a\le10^9)\) , \(q(q\le 4\cdot10^5)\) 次询问,每次从节点 \(v\) 出发,可以乘车经过任意连续一段海拔 \(> p\) 的边,之后便只能步行,求到达节点 \(1\) 所需的最短步行里程,强制在线。
思路
一开始乘车能够走到的节点集合即为按海拔降序建立 \(\texttt{Kruscal}\) 重构树后,以深度最小的权值 \(>p\) 的节点为根的子树。答案就是这些节点到 \(1\) 的最短路的最小值,于是我们可以先预处理出每个节点到 \(1\) 的最短路,然后在重构树上算出子树中最短路的最小值,之后对于每次询问,在重构树上倍增寻找深度最小的权值 \(>p\) 的节点即可 。
代码
#include<bits/stdc++.h>
#include<unordered_map>
#include<unordered_set>
using namespace std;
using LL = long long;
using LD = long double;
using ULL = unsigned long long;
using PII = pair<LL, LL>;
using TP = tuple<int, int, int>;
#define all(x) x.begin(),x.end()
#define mst(x,v) memset(x,v,sizeof(x))
#define mul(x,y) (1ll*(x)*(y)%mod)
#define mk make_pair
#define int LL
//#define double LD
//#define lc p*2
//#define rc p*2+1
#define endl '\n'
#define inf 0x3f3f3f3f
#define INF 0x3f3f3f3f3f3f3f3f
#pragma warning(disable : 4996)
#define IOS ios::sync_with_stdio(0),cin.tie(0),cout.tie(0)
const double eps = 1e-8;
const double pi = acos(-1);
const LL MOD = 1000000007;
const LL mod = 1004535809;
const int maxn = 600010;
const int maxm = 400010;
int TT, N, M, Q, K, S;
struct edge {
int to, l, a;
};
struct Edge {
int u, v, cost;
}es[maxm];
vector<edge>G[maxm];
vector<int>T[maxn];
void add_edge(int from, int to, int l, int a)
{
G[from].push_back(edge{ to,l,a });
G[to].push_back(edge{ from,l,a });
}
void add_edge(int from, int to)
{
T[from].push_back(to);
T[to].push_back(from);
}
bool cmp1(const Edge& x, const Edge& y)
{
return x.cost > y.cost;
}
int par[maxn];
void init(int n)
{
for (int i = 1; i <= n; i++)
par[i] = i;
}
int find(int x)
{
if (x == par[x])
return x;
return par[x] = find(par[x]);
}
void unite(int x, int y)
{
x = find(x), y = find(y);
if (x == y)
return;
par[y] = x;
}
bool same(int x, int y)
{
return find(x) == find(y);
}
int val[maxn], cntv, cnte;
void Kruskal()
{
sort(es + 1, es + M + 1, cmp1), init(cntv);
for (int i = 1; i <= M; i++)
{
Edge& e = es[i];
int u = e.u, v = e.v;
if (!same(u, v))
{
int fu = find(u), fv = find(v);
val[++cntv] = e.cost, par[cntv] = cntv;
add_edge(fu, cntv), add_edge(cntv, fv);
unite(cntv, fu), unite(cntv, fv);
}
if (cntv == N * 2 - 1)
break;
}
}
int d[maxn], fa[21][maxn], f[maxn];
void dijkstra()
{
for (int i = 1; i <= N; i++)
d[i] = INF;
priority_queue<PII, vector<PII>, greater<PII>>que;
d[1] = 0, que.push(PII(0, 1));
while (!que.empty())
{
PII p = que.top(); que.pop();
int v = p.second, dis = p.first;
if (dis > d[v])
continue;
for (auto& e : G[v])
{
if (d[v] + e.l < d[e.to])
{
d[e.to] = d[v] + e.l;
que.push(PII(d[e.to], e.to));
}
}
}
}
void dfs(int v, int p)
{
fa[0][v] = p;
if (v <= N)
f[v] = d[v];
else
f[v] = INF;
for (auto& to : T[v])
{
if (to == p)
continue;
dfs(to, v);
f[v] = min(f[to], f[v]);
}
}
void init()
{
dfs(cntv, 0);
for (int k = 0; k + 1 < 20; k++)
{
for (int v = 1; v <= cntv; v++)
{
if (fa[k][v] <= 0)
fa[k + 1][v] = 0;
else
fa[k + 1][v] = fa[k][fa[k][v]];
}
}
}
void solve()
{
dijkstra(), Kruskal(), init();
int ans = 0;
cin >> Q >> K >> S;
int v, p;
while (Q--)
{
cin >> v >> p;
v = (v + K * ans - 1) % N + 1;
p = (p + K * ans) % (S + 1);
while (true)
{
int lst = v;
for (int j = 20; j >= 0; j--)
{
if (fa[j][v] <= 0)
continue;
if (val[fa[j][v]] > p)
v = fa[j][v];
}
ans = f[v];
if (v == lst)
break;
}
cout << ans << endl;
}
}
signed main()
{
IOS;
cin >> TT;
while (TT--)
{
cin >> N >> M;
for (int i = 1; i <= N + M; i++)
T[i].clear();
for (int i = 1; i <= N; i++)
G[i].clear();
cntv = N, cnte = M;
int u, v, l, a;
for (int i = 1; i <= M; i++)
{
cin >> u >> v >> l >> a;
add_edge(u, v, l, a), es[i] = Edge{ u,v,a };
}
solve();
}
return 0;
}
标签:const,P4768,int,edge,que,using,归程,NOI2018,define 来源: https://www.cnblogs.com/Prgl/p/16515510.html