Luogu4768 NOI2018 归程 最短路、Kruskal重构树

传送门

题意:给出一个$N$个点、$M$条边的图,每条边有长度和海拔,$Q$组询问,每一次询问从$v$开始,经过海拔超过$p$的边所能到达的所有点中到点$1$的最短路的最小值,强制在线。$N \leq 2 \times 10^5 , M , Q \leq 4 \times 10^5$


关于$SPFA...$

与边的权值有关的连通块问题,经常可以考虑到$Kruskal$重构树。我们以海拔从大到小构建$Kruskal$重构树,那么对于每一次询问,可以到达的点就对应$Kruskal$重构树上的一棵子树。我们对于每一个点记录它的子树的叶子节点的最短路的最小值,每一次倍增找到询问对应的那一棵子树就能得到答案了。

#include<bits/stdc++.h>
//This code is written by Itst
using namespace std;

inline int read(){
    int a = 0;
    bool f = 0;
    char c = getchar();
    while(c != EOF && !isdigit(c)){
        if(c == '-')
            f = 1;
        c = getchar();
    }
    while(c != EOF && isdigit(c)){
        a = (a << 3) + (a << 1) + (c ^ '0');
        c = getchar();
    }
    return f ? -a : a;
}

const int MAXN = 400010;
struct edge{
    int start , end , hei;
}now[MAXN];
struct Edge{
    int end , upEd , w;
}Ed[MAXN << 1];
int head[MAXN] , minDis[MAXN] , fa[MAXN << 1] , jump[MAXN << 1][20] , val[MAXN << 1] , ans[MAXN << 1] , ch[MAXN << 1][2] , cntNode , cntEd , N , M , Q;
priority_queue < pair < int , int > > q;

bool operator <(edge a , edge b){
    return a.hei > b.hei;
}

int find(int a){
    return fa[a] == a ? a : (fa[a] = find(fa[a]));
}

inline void addEd(int a , int b , int c){
    Ed[++cntEd].end = b;
    Ed[cntEd].upEd = head[a];
    Ed[cntEd].w = c;
    head[a] = cntEd;
}

void Dijk(){
    memset(minDis , 0x7f , sizeof(minDis));
    minDis[1] = 0;
    q.push(make_pair(0 , 1));
    while(!q.empty()){
        pair < int , int > t = q.top();
        q.pop();
        if(-t.first > minDis[t.second])
            continue;
        for(int i = head[t.second] ; i ; i = Ed[i].upEd)
            if(minDis[Ed[i].end] > minDis[t.second] + Ed[i].w){
                minDis[Ed[i].end] = minDis[t.second] + Ed[i].w;
                q.push(make_pair(-minDis[Ed[i].end] , Ed[i].end));
            }
    }
}

void dfs(int node){
    if(!node)
        return;
    for(int i = 1 ; i <= 19 && jump[node][i - 1] ; ++i)
        jump[node][i] = jump[jump[node][i - 1]][i - 1];
    dfs(ch[node][0]);
    dfs(ch[node][1]);
}

inline int jumpToAll(int x , int h){
    for(int i = 19 ; i >= 0 ; --i)
        if(val[jump[x][i]] > h)
            x = jump[x][i];
    return x;
}

int main(){
#ifndef ONLINE_JUDGE
    freopen("4768.in" , "r" , stdin);
    //freopen("4768.out" , "w" , stdout);
#endif
    for(int T = read() ; T ; --T){
        memset(jump , 0 , sizeof(jump));
        memset(ch , 0 , sizeof(ch));
        memset(head , 0 , sizeof(head));
        cntEd = 0;
        N = read();
        M = read();
        for(int i = 1 ; i <= M ; i++){
            int a = read() , b = read() , c = read() , d = read();
            now[i].start = a;
            now[i].end = b;
            now[i].hei = d;
            addEd(a , b , c);
            addEd(b , a , c);
        }
        Dijk();
        for(int i = 1 ; i <= N ; i++){
            fa[i] = i;
            ans[i] = minDis[i];
        }
        sort(now + 1 , now + M + 1);
        cntNode = N;
        for(int i = 1 ; i <= M ; ++i)
            if(find(now[i].start) != find(now[i].end)){
                int a = find(now[i].start) , b = find(now[i].end);
                fa[a] = fa[b] = jump[a][0] = jump[b][0] = ++cntNode;
                ch[cntNode][0] = a;
                ch[cntNode][1] = b;
                val[cntNode] = now[i].hei;
                ans[cntNode] = min(ans[a] , ans[b]);
                fa[cntNode] = cntNode;
            }
        dfs(cntNode);
        int lastans = 0 , Q = read() , K = read() , S = read();
        while(Q--){
            int a = read() , b = read();
            a = (0ll + a + K * lastans - 1) % N + 1;
            b = (0ll + b + K * lastans) % (S + 1);
            int t = jumpToAll(a , b);
            printf("%d\n" , lastans = ans[t]);
        }
    }
    return 0;
}

 

转载于:https://www.cnblogs.com/Itst/p/10041099.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值