Luogu4768 NOI2018归程(最短路径+kruskal重构树)

  按海拔从大到小合并建出kruskal重构树,这样就能知道开车能到达哪些点,对这些点到1的最短路取min即可。最难的部分在于多组数据的初始化和数组大小的设置。

#include<iostream> 
#include<cstdio>
#include<cmath>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<queue>
#include<cassert>
using namespace std;
#define ll long long
#define N 200010
#define M 400010
#define inf 2000000010
char getc(){char c=getchar();while ((c<'A'||c>'Z')&&(c<'a'||c>'z')&&(c<'0'||c>'9')) c=getchar();return c;}
int gcd(int n,int m){return m==0?n:gcd(m,n%m);}
int read()
{
    int x=0,f=1;char c=getchar();
    while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();}
    while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
    return x*f;
}
int T,n,m,p[N],d[N],fa[N<<1],t,cnt;
bool flag[N];
struct data{int to,nxt,len,h;
}edge[M<<1];
void addedge(int x,int y,int z,int h){t++;edge[t].to=y,edge[t].nxt=p[x],edge[t].len=z,edge[t].h=h,p[x]=t;}
struct data2
{
    int x,d;
    bool operator <(const data2&a) const
    {
        return d>a.d;
    }
};
struct data3
{
    int x,y,z;
    bool operator <(const data3&a) const
    {
        return z>a.z;
    }
}e[M];
priority_queue<data2> q;
int find(int x){return fa[x]==x?x:fa[x]=find(fa[x]);}
void dijkstra()
{
    while (!q.empty()) q.pop();q.push((data2){1,0});
    for (int i=2;i<=n;i++) d[i]=inf;d[1]=0;
    memset(flag,0,sizeof(flag));
    for (;;)
    {
        while (!q.empty()&&flag[q.top().x]) q.pop();
        if (q.empty()) break;
        data2 x=q.top();q.pop();
        flag[x.x]=1;
        for (int i=p[x.x];i;i=edge[i].nxt)
        if (x.d+edge[i].len<d[edge[i].to])
        {
            d[edge[i].to]=x.d+edge[i].len;
            q.push((data2){edge[i].to,d[edge[i].to]});
        }
    }
}
namespace kruskal_tree
{
    int p[N<<1],t,fa[N<<1][20],val[N<<1],h[N<<1];
    struct data{int to,nxt,len;}edge[N<<1];
    void addedge(int x,int y){t++;edge[t].to=y,edge[t].nxt=p[x],p[x]=t;}
    void dfs(int k)
    {
        val[k]=k<=n?d[k]:inf;
        for (int i=p[k];i;i=edge[i].nxt)
        {
            fa[edge[i].to][0]=k;
            dfs(edge[i].to);
            val[k]=min(val[k],val[edge[i].to]);
        }
    }
    void build()
    {
        fa[cnt][0]=cnt;dfs(cnt);
        for (int j=1;j<20;j++)
            for (int i=1;i<=cnt;i++)
            fa[i][j]=fa[fa[i][j-1]][j-1];
    }
}
int main()
{
#ifndef ONLINE_JUDGE
    freopen("return.in","r",stdin);
    freopen("return.out","w",stdout);
    const char LL[]="%I64d\n";
#else
    const char LL[]="%lld\n";
#endif
    T=read();
    while (T--)
    {
        n=read(),m=read();
        for (int i=1;i<=n;i++) p[i]=0;t=0;
        for (int i=1;i<=m;i++)
        {
            int x=read(),y=read(),z=read(),h=read();
            e[i].x=x,e[i].y=y,e[i].z=h;
            addedge(x,y,z,h),addedge(y,x,z,h);
        }
        dijkstra();
        sort(e+1,e+m+1);
        for (int i=1;i<=n;i++) fa[i]=i,kruskal_tree::h[i]=inf,kruskal_tree::p[i]=0;cnt=n;kruskal_tree::t=0;
        for (int i=1;i<=m;i++)
        {
            int p=find(e[i].x),q=find(e[i].y);
            if (p!=q)
            {
                cnt++;fa[cnt]=fa[p]=fa[q]=cnt;kruskal_tree::p[cnt]=0;
                kruskal_tree::addedge(cnt,p),kruskal_tree::addedge(cnt,q);
                kruskal_tree::h[cnt]=e[i].z;
            }
        }
        kruskal_tree::build();
        int Q=read(),K=read(),S=read(),ans=0;
        while (Q--)
        {
            int x=(read()+K*ans-1)%n+1,y=(read()+K*ans)%(S+1);
            for (int j=19;~j;j--) if (kruskal_tree::h[kruskal_tree::fa[x][j]]>y) x=kruskal_tree::fa[x][j];
            printf("%d\n",ans=kruskal_tree::val[x]);
        }
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/Gloid/p/10177207.html