ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

P4768 [NOI2018] 归程

2022-07-24 21:34:18  阅读:130  来源: 互联网

标签:const P4768 int edge que using 归程 NOI2018 define


题目大意

\(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

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有