题意:
给你一个n个点m条边的无向图,每个点有两个权值,一个是长度一个是海拔。有q次询问,你在起点有一辆车,车可以在海拔高于l的路走,其余的路只能走过去,每次询问从x到1号点最少行走多少距离。n,m,q都是1e5量级的。强制在线。
题解:
没想到我在飞机上口胡了一个做法,竟然还真的把这个题过了。我这种蒟蒻做出NOI题了?
有了之前那个IOI的题,这个题就简单不少了。我们先预处理一个1号点到每个点的最短路。然后我们还是求一个Kruskal重构树,边按照海拔从大到小加入,因为海拔高的可以经过时海拔更低的才有可能可以经过。 我们求的过程中不仅记录每个节点的海拔,还记录这个节点为根的子树内到1号点最短路的最小值。这样我们就可在询问时在Kruskal重构树上倍增,然后找到正好不超过海拔限制的树上的点,然后这个点的记录的子树到1号点的最小值就是答案。
复杂度 O ( n l o g n ) O(nlogn) O(nlogn)。
代码:
#include <bits/stdc++.h>
using namespace std;
int n,m,qq,k,s,ans,hed[400010],cnt,hed1[400010],cnt1,T;
int dis[400010],vis[400010],fa[400010],f[400010][21],dep[400010],mn[400010];
int num,val[400010];
priority_queue<pair<int,int> > q;
struct node
{
int to,next,a,l,from;
}a[800010],b[800010];
inline int read()
{
int x=0;
char s=getchar();
while(s>'9'||s<'0')
s=getchar();
while(s>='0'&&s<='9')
{
x=x*10+s-'0';
s=getchar();
}
return x;
}
inline void add(int from,int to,int l,int x)
{
a[++cnt].to=to;
a[cnt].from=from;
a[cnt].next=hed[from];
a[cnt].l=l;
a[cnt].a=x;
hed[from]=cnt;
}
inline int cmp(node x,node y)
{
return x.a>y.a;
}
inline int getr(int x)
{
if(x==fa[x])
return x;
else
{
fa[x]=getr(fa[x]);
return fa[x];
}
}
inline void add1(int from,int to)
{
b[++cnt1].to=to;
b[cnt1].next=hed1[from];
hed1[from]=cnt1;
}
inline void dfs(int x)
{
for(int i=1;i<=20;++i)
f[x][i]=f[f[x][i-1]][i-1];
for(int i=hed1[x];i;i=b[i].next)
{
int y=b[i].to;
if(y==f[x][0])
continue;
f[y][0]=x;
dep[y]=dep[x]+1;
dfs(y);
}
}
inline int lca(int x,int y)
{
for(int i=20;i>=0;--i)
{
if(val[f[x][i]]>y)
x=f[x][i];
}
return x;
}
int main()
{
T=read();
while(T--)
{
memset(hed,0,sizeof(hed));
for(int i=1;i<=cnt;++i)
{
a[i].to=0;
a[i].next=0;
a[i].a=0;
a[i].l=0;
}
cnt=0;
memset(hed1,0,sizeof(hed1));
for(int i=1;i<=cnt1;++i)
{
b[i].to=0;
b[i].next=0;
b[i].a=0;
b[i].l=0;
}
memset(mn,0,sizeof(mn));
memset(val,0,sizeof(val));
cnt1=0;
n=read();
m=read();
for(int i=1;i<=m;++i)
{
int x,y,l,a;
x=read();
y=read();
l=read();
a=read();
add(x,y,l,a);
add(y,x,l,a);
}
q.push(make_pair(0,1));
memset(dis,0x3f,sizeof(dis));
memset(vis,0,sizeof(vis));
dis[1]=0;
while(!q.empty())
{
int x=q.top().second;
q.pop();
if(vis[x])
continue;
vis[x]=1;
for(int i=hed[x];i;i=a[i].next)
{
int y=a[i].to;
if(dis[y]>dis[x]+a[i].l)
{
dis[y]=dis[x]+a[i].l;
q.push(make_pair(-dis[y],y));
}
}
}
sort(a+1,a+cnt+1,cmp);
for(int i=1;i<=2*n;++i)
fa[i]=i;
for(int i=1;i<=n;++i)
{
mn[i]=dis[i];
val[i]=2e9;
}
num=n;
for(int i=1;i<=cnt;++i)
{
int fx=getr(a[i].from),fy=getr(a[i].to);
if(fx!=fy)
{
++num;
add1(num,fx);
add1(fx,num);
add1(fy,num);
add1(num,fy);
mn[num]=min(mn[fx],mn[fy]);
val[num]=a[i].a;
fa[fx]=fa[fy]=num;
}
}
memset(f,0,sizeof(f));
memset(dep,0,sizeof(dep));
dep[num]=1;
dfs(num);
ans=0;
qq=read();
k=read();
s=read();
for(int i=1;i<=qq;++i)
{
int x,y,z;
x=read();
y=read();
x=(x+k*ans-1)%n+1;
y=(y+k*ans)%(s+1);
z=lca(x,y);
ans=mn[z];
printf("%d\n",ans);
}
}
return 0;
}