[NOI2018]归程 - 最小生成树 - 最短路

做法是这样的,考虑kruskal的过程,每次合并两个联通块就新建一个点连向这个点并且边权是合并的时刻,这样时刻从下到上是递增的,每次询问的时候二分即可求出一个点在某个时刻所在的联通块的信息。

// luogu-judger-enable-o2
#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<utility>
#include<queue>
#include<climits>
#define mp make_pair
#define fir firse
#define sec second
#define gc getchar()
#define N 400010
#define M 400010
#define LOG 22
#define INF INT_MAX
using namespace std;
typedef pair<int,int> pii;
inline int inn()
{
    int x,ch;while((ch=gc)<'0'||ch>'9');
    x=ch^'0';while((ch=gc)>='0'&&ch<='9')
        x=(x<<1)+(x<<3)+(ch^'0');return x;
}
struct edges{
    int to,pre,wgt;
}e[M<<1];int h[N],d[N],etop;
priority_queue<pii> q;int vis[N];
inline int add_edge(int u,int v,int w)
{   return e[++etop].to=v,e[etop].pre=h[u],h[u]=etop,e[etop].wgt=w; }
struct Es{
    int u,v,a;
    inline bool operator<(const Es &e)const{return a>e.a;}
}es[M];int fa[N],dpt[N];
inline int dijkstra(int s,int n)
{
    while(!q.empty()) q.pop();
    for(int i=1;i<=n;i++) d[i]=INF;
    memset(vis,0,sizeof(int)*(n+1));
    d[s]=0,q.push(mp(0,s));
    while(!q.empty())
    {
        int x=q.top().sec;q.pop();
        if(vis[x]) continue;vis[x]=1;
        for(int i=h[x],y;i;i=e[i].pre)
            if(d[y=e[i].to]>d[x]+e[i].wgt)
                d[y]=d[x]+e[i].wgt,q.push(mp(-d[y],y));
    }
    return 0;
}
inline int findf(int x)
{
    int fx=x,y;while(fx^fa[fx]) fx=fa[fx];
    while(x^fx) y=fa[x],fa[x]=fx,x=y;return x;
}
int val[N][LOG],up[N][LOG];
inline int kruskal(int n,int m)
{
    sort(es+1,es+m+1);int c=n;
    for(int i=1;i<=2*n;i++) fa[i]=i;
    for(int i=1,ing=0;i<=m&&ing<n-1;i++)
    {
        int x=findf(es[i].u),y=findf(es[i].v),a=es[i].a;
        if(x^y) val[x][0]=val[y][0]=a,fa[x]=fa[y]=++c,
        d[up[x][0]=up[y][0]=c]=min(d[x],d[y]),ing++;
    }
    for(int i=0;i<LOG;i++) up[c][i]=0,val[c][i]=-1;
    for(int i=c;i>=1;i--) dpt[i]=dpt[up[i][0]]+1;
    for(int i=c-1;i>=1;i--) for(int j=1;j<LOG;j++)
        up[i][j]=up[up[i][j-1]][j-1],val[i][j]=min(val[i][j-1],val[up[i][j-1]][j-1]);
    return 0;
}
inline int getLCA(int x,int y)
{
    if(dpt[x]<dpt[y]) swap(x,y);
    for(int i=LOG-1;i>=0;i--)
        if(dpt[up[x][i]]>=dpt[y]) x=up[x][i];
    if(x==y) return x;
    for(int i=LOG-1;i>=0;i--)
        if(up[x][i]^up[y][i]) x=up[x][i],y=up[y][i];
    return up[x][0];
}
int main()
{
    for(int T=inn();T;T--)
    {
        int n=inn(),m=inn();
        memset(h,0,sizeof(int)*(n+1)),etop=0;
        for(int i=1,x,y,w;i<=m;i++)
            x=es[i].u=inn(),y=es[i].v=inn(),w=inn(),
            es[i].a=inn(),add_edge(x,y,w),add_edge(y,x,w);
        dijkstra(1,n),kruskal(n,m);
        for(int q=inn(),las=0,k=inn(),mxp=inn();q;q--)
        {
            int x=(inn()+k*las-1)%n+1,p=(inn()+k*las)%(mxp+1),y=x;
            for(int i=LOG-1;i>=0;i--) if(val[y][i]>p) y=up[y][i];
            printf("%d\n",las=d[y]*(dpt[getLCA(1,x)]<=dpt[y]));
        }
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/Mys_C_K/article/details/81141178