p4768 [NOI2018]归程

分析

先求出每个点到终点的最短路

我们按照海拔从大到小排序

然后求出kruskal重构树

每次答案就是一个可行子树中的最短路的最小值

代码

#include<bits/stdc++.h>
using namespace std;
#define fi first
#define se second
#define mp make_pair
#define li long long
int head[800100],nxt[800100],to[800100],w[800100],n,m,cnt;
int dis[800100],vis[800100],tot,pr[800100][23],fa[800100],val[800100];
vector<int>v[800100];
struct node {
    int x,y,z,w;
};
node d[400100];
inline bool cmp(const node x,const node y){return x.w>y.w;}
inline int sf(int x){return fa[x]==x?x:fa[x]=sf(fa[x]);}
struct Kruskal_Tree {
    inline void build(){
      int i,j,k=0;
      for(i=1;i<=n+m;i++)v[i].clear();
      tot=n;sort(d+1,d+m+1,cmp);
      for(i=1;i<=n+m;i++)fa[i]=i;
      for(i=1;i<=m;i++){
          int x=d[i].x,y=d[i].y,z=d[i].w;
          if(sf(x)!=sf(y)){
            v[++tot].push_back(sf(x));
            v[tot].push_back(sf(y));
            fa[sf(x)]=fa[sf(y)]=tot;
            val[tot]=z;
            k++;
        }
        if(k==n-1)break;
      }
    }
    inline void dfs(int x,int fa){
      pr[x][0]=fa;
      for(int i=0;i<v[x].size();i++)
        if(v[x][i]!=fa){
          dfs(v[x][i],x);
          dis[x]=min(dis[x],dis[v[x][i]]);
        }
    }
    inline void deal(){
      for(int i=1;i<=20;i++)
        for(int j=1;j<=tot;j++)
          pr[j][i]=pr[pr[j][i-1]][i-1];
    }
    inline int que(int x,int y){
      for(int i=20;i>=0;i--)if(pr[x][i]&&val[pr[x][i]]>y)x=pr[x][i];
      return x;
    }
};
Kruskal_Tree T;
priority_queue<pair<int,int> >q;
inline void init(){
    cnt=0;
    memset(head,0,sizeof(head));
    memset(dis,0x7f,sizeof(dis));
    memset(vis,0,sizeof(vis));
    memset(pr,0,sizeof(pr));
}
inline void add(int x,int y,int z){
    nxt[++cnt]=head[x];
    head[x]=cnt;
    to[cnt]=y;
    w[cnt]=z;
    nxt[++cnt]=head[y];
    head[y]=cnt;
    to[cnt]=x;
    w[cnt]=z;
}
inline void dij(){
    dis[1]=0;
    q.push(mp(0,1));
    while(!q.empty()){
      int x=q.top().se;
      q.pop();
      if(vis[x])continue;
      vis[x]=1;
      for(int i=head[x];i;i=nxt[i]){
        if(dis[to[i]]>(li)(dis[x]+w[i])){
          dis[to[i]]=dis[x]+w[i];
          q.push(mp(-dis[to[i]],to[i]));
        }
      }
    }
}
int main(){
    int i,j,k,t,x,y,z,q,s;
    scanf("%d",&t);
    while(t--){
      init();
      scanf("%d%d",&n,&m);
      for(i=1;i<=m;i++){
          scanf("%d%d%d%d",&d[i].x,&d[i].y,&d[i].z,&d[i].w);
          add(d[i].x,d[i].y,d[i].z);
      }
      dij();
      T.build();
      T.dfs(tot,0);
      T.deal();
      int lastans=0;
      scanf("%d%d%d",&q,&k,&s);
      while(q--){
          scanf("%d%d",&x,&y);
          x=(x+1ll*k*lastans%n-1)%n+1;
          y=(y+1ll*k*lastans%(s+1))%(s+1);
          lastans=dis[T.que(x,y)];
          printf("%d\n",lastans);
      }
    }
    return 0;
}

 

posted @ 2019-09-19 10:00  水题收割者  阅读(169)  评论(0编辑  收藏  举报