[NOI2018] 归程 解题报告

题面

步行的最小距离很容易求,dij随便求一下每个点的最短路,然后找到与 \(v\) 能相互坐车到达的点,对这些点的最短路都有可能是答案,取个 \(\min\) 即可。

所以本题最大的问题是怎么找到在水位线为 \(p\) 时,与 \(v\) 能相互坐车到达的点。可以想到只保留海拔大于 \(p\) 的边,因为只要考虑连通性且对于所有的 \(p\) 都需要考虑,想到 Kruskal 重构树。
Kruskal 重构树上用倍增找到深度最浅的海拔大于 \(p\) 的边,这个边对应的点的子树内的点的距离最小值即为答案。

点击查看代码
#include<bits/stdc++.h>
#define ull unsigned long long
#define ll long long
#define pdi pair<double,int>
#define pii pair<int,int>
#define pb push_back
#define mp make_pair
#define eps 1e-9
using namespace std;
namespace IO{
    template<typename T>
    inline void read(T &x){
        x=0;
        int f=1;
        char ch=getchar();
        while(ch>'9'||ch<'0'){
            if(ch=='-'){
                f=-1;
            }
            ch=getchar();
        }
        while(ch>='0'&&ch<='9'){
            x=x*10+(ch-'0');
            ch=getchar();
        }
        x=(f==1?x:-x);
    }
    template<typename T>
    inline void write(T x){
        if(x<0){
            putchar('-');
            x=-x;
        }
        if(x>=10){
            write(x/10);
        }
        putchar(x%10+'0');
    }
    template<typename T>
    inline void write_endl(T x){
        write(x);
        putchar('\n');
    }
    template<typename T>
    inline void write_space(T x){
        write(x);
        putchar(' ');
    }
}
using namespace IO;
const int N=4e5+10,M=4e5+10,inf=2.1e9,Lg=20;
int n,m,cnt,h[N<<1],dsu[N<<1];
int fa[N][Lg+5],dep[N];
vector<int>G[N<<1];
vector<pii>E[N];
struct edge{
    int u,v,w,h;
}e[M];
bool cmp(edge x,edge y){
    return x.h>y.h;
}
int getfa(int u){
    if(dsu[u]!=u){
        dsu[u]=getfa(dsu[u]);
    }
    return dsu[u];
}
void clear(){
    for(int i=1;i<=cnt;i++){
        dep[i]=h[i]=0,dsu[i]=i;
        vector<int>().swap(G[i]);
        vector<pii>().swap(E[i]);
        for(int j=0;j<=Lg;j++){
            fa[i][j]=0;
        }
    }
}
int d[N<<1],b[N<<1];
void dij(){
    for(int i=1;i<=n;i++){
        d[i]=inf;
        b[i]=0;
    }
    d[1]=0;
    priority_queue<pii>q;
    q.push(mp(0,1));
    while(!q.empty()){
        int u=q.top().second;
        q.pop();
        if(b[u]){
            continue;
        }
        b[u]=1;
        for(auto x:E[u]){
            int v=x.first,w=x.second;
            if(d[v]>d[u]+w){
                d[v]=d[u]+w;
                q.push(mp(-d[v],v));
            }
        }
    }
}
void make_tree(int u){
    for(int i=1;i<=Lg;i++){
        fa[u][i]=fa[fa[u][i-1]][i-1];
    }
    for(auto v:G[u]){
        if(dep[v]){
            continue;
        }
        dep[v]=dep[u]+1;
        fa[v][0]=u;
        make_tree(v);
        d[u]=min(d[u],d[v]);
    }
}
int find(int st,int p){
    for(int i=Lg;i>=0;i--){
        if(h[fa[st][i]]>p){
            st=fa[st][i];
        }
    }
    return st;
}
void solve(){
    read(n),read(m);
    cnt=n;
    for(int i=1;i<=m;i++){
        read(e[i].u),read(e[i].v),read(e[i].w),read(e[i].h);
    }
    for(int i=1;i<=n;i++){
        h[i]=inf;
        dsu[i]=i;
    }
    sort(e+1,e+m+1,cmp);
    for(int i=1;i<=m;i++){
        int u=e[i].u,v=e[i].v;
        u=getfa(u),v=getfa(v);
        if(u!=v){
            dsu[v]=dsu[u]=dsu[++cnt]=cnt;
            h[cnt]=e[i].h;
            G[cnt].pb(u),G[cnt].pb(v);
            d[cnt]=inf;
        }
    }
    for(int i=1;i<=m;i++){
        E[e[i].u].pb(mp(e[i].v,e[i].w));
        E[e[i].v].pb(mp(e[i].u,e[i].w));
    }
    dij();
    dep[cnt]=1;
    make_tree(cnt);
    int q,opt,s;
    read(q),read(opt),read(s);
    int lstans=0;
    while(q--){
        int st,p;
        read(st),read(p);
        st=(st+opt*lstans-1)%n+1;
        p=(p+opt*lstans)%(s+1);
        int pos=find(st,p);
        lstans=d[pos];
        write_endl(lstans);
    }
    clear();
}
signed main(){
    #ifndef ONLINE_JUDGE
        freopen("1.in","r",stdin);
        freopen("1.out","w",stdout);
    #endif
    int t;
    read(t);
    while(t--){
        solve();
    }
    return 0;
}
posted @ 2023-05-13 14:58  luo_shen  阅读(33)  评论(0)    收藏  举报