题目描述:
n个点,m条边的无向图,每个边有权值和高度。
每次询问给出出发点和最低高度,当边的高度高于最低高度时才可以通行,问从出发点可以到达离点1最近的点距离是多少
题目分析:
由于是无向图,先对点1跑单源最短路。
对图做克鲁斯卡尔重构树,由于是高于某个值才能通行,对边权降序排列,做小根堆,对出发的点走到最低不能走的位置,对子树内询问最小的距离即可
题目链接:
AC代码:
#include <cstdio>
#include <algorithm>
#include <queue>
#include <cstring>
const int maxm=420000,INF=2147483646;
struct node{
int u,v,w;
}edge[maxm];
struct Node{
int dis,id;
bool operator <(const Node &a)const
{
return a.dis<dis;
}
};
int head[maxm],to[maxm*2],net[maxm*2],cost[maxm*2];
int dis[maxm],vis[maxm];
int fa[maxm],fat[maxm][20],val[maxm][20];
int cnt,n,m,sz;
std::priority_queue<Node> dl;
inline void addedge(int u,int v,int c){to[++cnt]=v,cost[cnt]=c,net[cnt]=head[u],head[u]=cnt;}
inline bool comp(node x,node y){return x.w>y.w;}
int find(int x){return x==fa[x]?x:fa[x]=find(fa[x]);}
inline void dijskra(int st)
{
memset(dis,0x3f,sizeof(dis));
memset(vis,0,sizeof(vis));
dis[st]=0;
dl.push((Node){0,st});
while(!dl.empty())
{
Node now=dl.top();
dl.pop();
if(vis[now.id]) continue;
vis[now.id]=1;
for(int i=head[now.id];i;i=net[i])
if(!vis[to[i]]&&dis[to[i]]>dis[now.id]+cost[i])
{
dis[to[i]]=dis[now.id]+cost[i];
dl.push(Node{dis[to[i]],to[i]});
}
}
}
inline void kruskal()
{
sz=n;
for(int i=1;i<=n;i++) fa[i]=i;
std::sort(edge+1,edge+m+1,comp);
for(int i=1;i<=m;i++)
{
int rootu=find(edge[i].u),rootv=find(edge[i].v);
if(rootu!=rootv)
{
int newroot=++sz;
fa[rootu]=fa[rootv]=fa[newroot]=newroot;
fat[rootu][0]=fat[rootv][0]=newroot;
val[rootu][0]=val[rootv][0]=edge[i].w;
dis[newroot]=std::min(dis[rootu],dis[rootv]);
}
}
for(int j = 1;j<=18;j++)
for(int i=1;i<=sz;i++)
fat[i][j]=fat[fat[i][j-1]][j-1],val[i][j]=std::min(val[i][j-1],val[fat[i][j-1]][j-1]);
}
inline int slove(int nv,int np)
{
for(int i=18;i>=0;i--)
if(val[nv][i]>np) nv=fat[nv][i];
//printf("S:%d\n",nv);
return dis[nv];
}
inline void work()
{
memset(head,0,sizeof(head));
//memset(val,0x3f,sizeof(val));
memset(fat,0,sizeof(fat));
cnt=0;
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++)
{
int u,v,l,a;
scanf("%d%d%d%d",&u,&v,&l,&a);
addedge(u,v,l),addedge(v,u,l);
edge[i]=(node){u,v,a};
}
dijskra(1);
kruskal();
int q,k,s,lastans=0;
scanf("%d%d%d",&q,&k,&s);
for(int i=1;i<=q;i++)
{
int v0,p0;
scanf("%d%d",&v0,&p0);
int nv=(v0+k*lastans-1)%n+1;
int np=(p0+k*lastans)%(s+1);
printf("%d\n",lastans=slove(nv,np));
}
}
int main()
{
//freopen("1.txt","w",stdout);
int t;
scanf("%d",&t);
while(t--) work();
return 0;
}