[NOI 2018] 归程

[题目链接]

         https://www.lydsy.com/JudgeOnline/problem.php?id=5415

[算法]

         对于v到1的1条合法路径 , 我们将其分为两段考虑

         1. v -> u , 该路径上的最短边长大于等于P

         2. u -> 1

         显然 , 我们要求所有这样的路径中distu的最小值

         不妨先用Dijkstra算法求出单源最短路 , 然后求出kruskal重构树

         对于每组询问 , 将v在kruskal重构树上倍增 , 倍增到一个深度最小的点且该点的权值最小

         那么答案即为这棵子树中dist的最小值

         时间复杂度 : O(T(N+M+Q)logN)

[代码]

       

#include<bits/stdc++.h>
using namespace std;
const int N = 2e5 + 10;
const int M = 4e5 + 10;
const int MAXLOG = 20;
typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
const ll inf = 1e18;

struct info
{
    int u , v , w;
    int h;
} a[M];

struct edge
{
    int to , nxt;
} e[M << 1];

int n , m , tot , q , s , k , cnt;
int head[N << 1] , val[N << 1] , father[N << 1][MAXLOG] , depth[N << 1] , fa[N << 1];
ll dist[N << 1] , mn[N << 1];
vector< pair<int , int> > G[N];

template <typename T> inline void chkmin(T &x , T y) { x = min(x , y); }
template <typename T> inline void chkmax(T &x , T y) { x = max(x , y); }
template <typename T> inline void read(T &x)
{
   T f = 1; x = 0;
   char c = getchar();
   for (; !isdigit(c); c = getchar()) if (c == '-') f = -f;
   for (; isdigit(c); c = getchar()) x = (x << 3) + (x << 1) + c - '0';
   x *= f;
}
inline void dijkstra(int s)
{
    static bool visited[N << 1];
    priority_queue< pair<ll , int> , vector< pair<ll , int> > , greater< pair<ll , int> > > q;
    q.push(make_pair(0 , s));
    for (int i = 1; i <= n; i++) 
    {
        dist[i] = inf;
        visited[i] = false;
    }
    dist[s] = 0;
    while (!q.empty())
    {
        int cur = q.top().second;
        q.pop();
        if (visited[cur]) continue;
        visited[cur] = true;
        for (unsigned i = 0; i < G[cur].size(); i++)
        {
            int to = G[cur][i].first , w = G[cur][i].second;
            if (dist[cur] + w < dist[to])
            {
                dist[to] = dist[cur] + w;
                q.push(make_pair(dist[to] , to));
            }
        }
    }
}
inline bool cmp(info a , info b)
{
    return a.h > b.h;
}
inline void dfs(int u , int par)
{
    father[u][0] = par;
    depth[u] = depth[par] + 1;
    for (int i = 1; i < MAXLOG; i++)
        father[u][i] = father[father[u][i - 1]][i - 1];
    if (!head[u]) // leaf
    {
        mn[u] = dist[u];
        return;
    }
    mn[u] = inf;
    for (int i = head[u]; i; i = e[i].nxt)
    {
        int v = e[i].to;
        if (v != par) dfs(v , u);
        chkmin(mn[u] , mn[v]);
    }
}
inline int getroot(int x)
{
    if (fa[x] == x) return x;
    else return fa[x] = getroot(fa[x]);
}
inline void addedge(int u , int v)
{
    ++tot;
    e[tot] = (edge){v , head[u]};
    head[u] = tot;
}
inline void kruskal()
{
    int tot = 0;
    cnt = n;
    for (int i = 1; i <= n; i++) fa[i] = i;
    for (int i = 1; i <= m; i++)
    {        
        int fu = getroot(a[i].u) , fv = getroot(a[i].v);
        if (fu != fv)
        {
            fa[fu] = fv;
            addedge(++cnt , fu);
            addedge(cnt , fv);
            val[cnt] = a[i].h;
            fa[fu] = fa[fv] = fa[cnt] = cnt;
            ++tot;
        } 
        if (tot == n - 1) break;
    } 
    dfs(cnt , 0);
}
 
int main()
{
    
    int T;
    read(T);
    while (T--)
    {
        read(n); read(m);    
        tot = 0;
        memset(head , 0 , sizeof(head));
        for (int i = 1; i <= n; i++) G[i].clear();
        for (int i = 1; i <= m; i++)
        {
            read(a[i].u);
            read(a[i].v);
            read(a[i].w);
            read(a[i].h);
            G[a[i].u].push_back(make_pair(a[i].v , a[i].w));
            G[a[i].v].push_back(make_pair(a[i].u , a[i].w));
        }
        sort(a + 1 , a + m + 1 , cmp);
        dijkstra(1);
        kruskal();
        read(q); read(k); read(s);
        int lastans = 0;
        while (q--)
        {
            int v0 , p0;
            read(v0); read(p0);
            int v = (v0 + 1ll * k * lastans - 1) % n + 1 , 
                p = (p0 + 1ll * k * lastans) % (s + 1);
            for (int i = MAXLOG - 1; i >= 0; i--)
            {
                if (depth[father[v][i]] > 0 && val[father[v][i]] > p)
                    v = father[v][i];
            }
            printf("%lld\n" , lastans = mn[v]);
        }
    }
    
    return 0;
}

         

猜你喜欢

转载自www.cnblogs.com/evenbao/p/10372257.html