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;
}
本文来自博客园,作者:zhouhuanyi,转载请注明原文链接:https://www.cnblogs.com/zhouhuanyi/p/16983748.html

浙公网安备 33010602011771号