Loading

P4768 [NOI2018]归程

链接:https://www.luogu.com.cn/problem/P4768

题目描述:给定\(n\)个点\(m\)条边的带权无向图,你有一辆车,可以走所有权值大于\(x\)的点,你也可以丢弃车步行,然后就不能使用车了,\(q\)组询问,每组询问求一个点到达\(1\)\(x=X\)时步行路径最小值。

题解:直接最小生成树上倍增无法跳子树,那么我们可以考虑一个无根的东西,即\(kruskal\)重构树。考虑建出\(kruskal\)重构树,然后将每一个新建点赋值为所表示的所有点的到\(1\)最短路的最小值,这时跳倍增就不会错了。

#include<iostream>
#include<cstdio>
#include<queue>
#include<algorithm>
using namespace std;
struct kru
{
  int u,v,data;
  bool operator < (const kru &a)const
  {
    return data>a.data;
  }
};
struct node
{
  int v,nxt,data;
};
node edge[800001];
kru edges[400001];
int n,m,len,head[200001];
int read()
{
  char c=0;
  int sum=0;
  while (c<'0'||c>'9')
      c=getchar();
  while ('0'<=c&&c<='9')
    {
      sum=sum*10+c-'0';
      c=getchar();
    }
  return sum;
}
void add(int x,int y,int z)
{
  edge[++len].v=y;
  edge[len].data=z;
  edge[len].nxt=head[x];
  head[x]=len;
  return;
}
struct reads
{
  int num,data;
  bool operator < (const reads &a)const
  {
    return data>a.data;
  }
};
reads tmp;
reads make_reads(int x,int y)
{
  tmp.num=x;
  tmp.data=y;
  return tmp;
}
int dis[400001],F[400001];
bool vis[200001];
void dijkstra()
{
  priority_queue<reads>q;
  int top;
  for (int i=1;i<=n;++i)
    dis[i]=1e9,vis[i]=0;
  dis[1]=0;
  q.push(make_reads(1,0));
  while (!q.empty())
    {
      top=q.top().num;
      q.pop();
      if (vis[top])
	continue;
      vis[top]=1;
      for (int i=head[top];i>0;i=edge[i].nxt)
	if (dis[edge[i].v]>dis[top]+edge[i].data)
	  {
	    dis[edge[i].v]=dis[top]+edge[i].data;
	    q.push(make_reads(edge[i].v,dis[edge[i].v]));
	  }
    }
  return;
}
int N,rt[400001],fa[400001][21];
int find(int x)
{
  if (rt[x]==x)
    return x;
  return rt[x]=find(rt[x]);
}
void unionn(int x,int y)
{
  rt[x]=y;
}
void make_kruskal_tree()
{
  N=n;
  for (int i=1;i<=2*n-1;++i)
    {
      rt[i]=i;
      fa[i][0]=0;
    }
  sort(edges+1,edges+m+1);
  for (int i=1;i<=m;++i)
    if (find(edges[i].u)!=find(edges[i].v))
      {
	F[++N]=edges[i].data;
	dis[N]=min(dis[find(edges[i].u)],dis[find(edges[i].v)]);
        fa[find(edges[i].u)][0]=N;
	fa[find(edges[i].v)][0]=N;
	unionn(find(edges[i].u),N);
	unionn(find(edges[i].v),N);
      }
  return;
}
int main()
{
  int T,x,y,lastans;
  T=read();
  while (T--)
    {
      lastans=len=0;
      n=read(),m=read();
      for (int i=1;i<=n;++i)
	head[i]=0;
      for (int i=1;i<=m;++i)
	{
	  edges[i].u=read(),edges[i].v=read(),x=read(),edges[i].data=read();
	  add(edges[i].u,edges[i].v,x);
	  add(edges[i].v,edges[i].u,x);
	}
      dijkstra();
      make_kruskal_tree();
      for (int j=1;j<=20;++j)
	for (int i=1;i<=2*n-1;++i)
	  fa[i][j]=fa[fa[i][j-1]][j-1];
      int q,k,s;
      q=read(),k=read(),s=read();
      while (q--)
	{
	  x=read(),y=read();
	  x=(x+k*lastans-1)%n+1;
	  y=(y+k*lastans)%(s+1);
          for (int i=20;i>=0;--i)
	    if (fa[x][i]!=0&&F[fa[x][i]]>y)
	      x=fa[x][i];
	  lastans=dis[x];
	  printf("%d\n",lastans=dis[x]);
	}
    }
  return 0;
}
posted @ 2022-12-14 21:58  zhouhuanyi  阅读(38)  评论(0)    收藏  举报