背景:
今天真得好累。
题目传送门:
https://www.luogu.org/problem/P4768
题意:
n
n
n个点,
m
m
m条边,有边权,一个表示长度,一个表示高度。
多组询问,每组询问问从
x
x
x点出发,当前的积水高度是
y
y
y,可以开车经过边的高度必须严格大于
y
y
y,当遇到边的高度小于等于
y
y
y时,就会弃掉汽车,选择步行,求步行到
1
1
1号点的最小距离。
思路:
显然的克鲁斯卡尔重构树的应用。
不弃车时一定是一个联通块,而且是最大的联通块,而答案一定是这个联通块中到
1
1
1点的最小距离。
那么我们先用迪杰斯特拉(丧心病狂的出题人卡
spfa
\text{spfa}
spfa)预处理出每一个点到
1
1
1号点的最短路,然后按照边的高度降序(因为高度越高越好),用克鲁斯卡尔重构树将这些边处理。最后倍增找到一个尽可能远的祖先,然后在这个子树内寻找距离的最小值即可。
建议大家在
loj
\text{loj}
loj上交,可以评测所有的数据,但是要用文件输入输出。
代码:
#include<cstdio>
#include<cstring>
#include<queue>
#include<algorithm>
#define I inline
#define R register
using namespace std;
struct node3
{
int x,d;
friend bool operator <(node3 x,node3 y)
{
return x.d>y.d;
}
};
priority_queue<node3> F;
struct node1{int x,y,l,next;} a[800010];
struct node2{int x,y,z,l;} b[800010];
int last[400010],val[400010],fa[400010],f[400010][20],dis[400010],son[400010][2];
bool bz[400010];
int n,m,q,op,p,len;
bool cmp(node2 x,node2 y)
{
return x.z>y.z;
}
I void clear()
{
len=0;
memset(last,0,sizeof(last));
memset(fa,0,sizeof(fa));
memset(f,0,sizeof(f));
}
I int find(int x)
{
return fa[x]==x?x:fa[x]=find(fa[x]);
}
I void ins(int x,int y,int l)
{
a[++len]=(node1){x,y,l,last[x]}; last[x]=len;
}
I void spfa()
{
memset(dis,63,sizeof(dis));
dis[1]=0;
memset(bz,false,sizeof(bz));
F.push((node3){1,0});
while(!F.empty())
{
node3 TOP=F.top();
F.pop();
if(bz[TOP.x]) continue;
bz[TOP.x]=true;
for(R int i=last[TOP.x];i;i=a[i].next)
{
int y=a[i].y;
if(dis[y]>dis[TOP.x]+a[i].l)
{
dis[y]=dis[TOP.x]+a[i].l;
F.push((node3){y,dis[y]});
}
}
}
}
void dfs(int x)
{
if(x<=n) return;
f[son[x][0]][0]=x,f[son[x][1]][0]=x;
dfs(son[x][0]),dfs(son[x][1]);
dis[x]=min(dis[son[x][0]],dis[son[x][1]]);
}
I void init()
{
spfa();
sort(b+1,b+m+1,cmp);
int cnt=n;
for(R int i=1;i<=m;i++)
{
int t1=find(b[i].x),t2=find(b[i].y);
if(t1==t2) continue;
fa[++cnt]=cnt;
fa[t1]=fa[t2]=cnt;
val[cnt]=b[i].z;
son[cnt][0]=t1,son[cnt][1]=t2;
if(cnt==n+n-1) break;
}
dfs(cnt);
for(R int i=1;i<=18;i++)
for(R int j=1;j<=cnt;j++)
f[j][i]=f[f[j][i-1]][i-1];
}
I int find_(int x,int y)
{
for(R int i=18;i>=0;i--)
if(f[x][i]&&val[f[x][i]]>y) x=f[x][i];
return x;
}
I char getc()
{
static char buf[1<<20],*fs,*ft;
return(fs==ft&&(ft=(fs=buf)+fread(buf,1,1<<20,stdin)),fs==ft)?EOF:*fs++;
}
I void read(int &x)
{
char ch=getc(),f=1;
for(x=0;ch<'0'||ch>'9';ch=getc());
for(;ch>='0'&&ch<='9';ch=getc())
x=((x+(x<<2))<<1)+(ch^0x30);
}
static const int BUF=50000000;
char buf[BUF],*h=buf;
inline void put(char ch)
{
h==buf+BUF?(fwrite(buf,1,BUF,stdout),h=buf):0;
*h++=ch;
}
inline void putint(int num)
{
static char _buf[30];
sprintf(_buf,"%d",num);
for(char *s=_buf;*s;s++)put(*s);
}
inline void finish()
{
fwrite(buf,1,h-buf,stdout);
}
int main()
{
int T,x,y,lastans;
read(T);
while(T--)
{
clear();
read(n),read(m);
for(R int i=1;i<=n;i++)
fa[i]=i;
for(R int i=1;i<=m;i++)
{
read(b[i].x),read(b[i].y),read(b[i].l),read(b[i].z);
ins(b[i].x,b[i].y,b[i].l),ins(b[i].y,b[i].x,b[i].l);
}
init();
read(q),read(op),read(p);
lastans=0;
for(R int i=1;i<=q;i++)
{
read(x),read(y);
x=(x+op*lastans-1)%n+1;
y=(y+op*lastans)%(p+1);
int t=find_(x,y);
putint(lastans=dis[find_(x,y)]),put('\n');
}
}
finish();
}