k
r
u
s
k
a
l
kruskal
kruskal重构树不会的话珂以看这篇题解qwq
这道题考虑把边按照海拔从大到小排序,让重构的树成为一棵以海拔为关键字的小根堆。
重构树的每个节点记录两个信息
v
a
l
,
d
i
s
val,dis
val,dis,分别表示当前节点子树内最小的海拔和最小到
1
1
1的距离,其中叶子节点(即原图的节点)
v
a
l
=
0
val=0
val=0。
对于每个询问给出的水位
p
p
p,假设重构树上有一个节点
u
u
u使得
v
a
l
[
u
]
>
=
p
val[u]>=p
val[u]>=p且
v
a
l
[
f
a
]
<
=
p
val[fa]<=p
val[fa]<=p,说明当且仅当
x
,
y
x,y
x,y在
u
u
u的子树内时,
x
x
x能开车到达
y
y
y(
y
y
y也能开车到达
x
x
x)
所以此时答案为
d
i
s
[
u
]
dis[u]
dis[u](即
u
u
u的子树内的节点到
1
1
1的距离的最小值)
原图中节点的
d
i
s
dis
dis珂以一遍
d
i
j
k
s
t
r
a
dijkstra
dijkstra求出来,非叶子节点的
d
i
s
dis
dis和
v
a
l
val
val珂以
d
f
s
dfs
dfs一遍qwq。
时间复杂度:
O
(
(
n
+
m
+
q
)
l
o
g
n
)
O((n+m+q)logn)
O((n+m+q)logn) (
d
i
j
k
s
t
r
a
dijkstra
dijkstra
O
(
(
n
+
m
)
l
o
g
n
)
O((n+m)logn)
O((n+m)logn),询问
O
(
q
l
o
g
n
)
O(qlogn)
O(qlogn))
代码
注: l o j loj loj上记得加 f r e o p e n freopen freopen qwq
#include<stdio.h>
#include<cstring>
#include<algorithm>
#include<math.h>
#include<vector>
#include<queue>
#define re register int
#define rl register ll
using namespace std;
typedef long long ll;
int read() {
re x=0,f=1;
char ch=getchar();
while(ch<'0' || ch>'9') {
if(ch=='-') f=-1;
ch=getchar();
}
while(ch>='0' && ch<='9') {
x=10*x+ch-'0';
ch=getchar();
}
return x*f;
}
inline void write(int x) {
if(x>9) write(x/10);
putchar(x%10+'0');
}
namespace I_Love {
const int Size=400005;
int n,m,q,k,s,cnt,head[Size];
struct Edge {
int u,v,h,t,next;
//h:海拔 t:长度
} w[Size<<1],tree[Size<<1];
void AddEdge(int u,int v,int h,int t) {
w[++cnt].u=u;
w[cnt].v=v;
w[cnt].h=h;
w[cnt].t=t;
w[cnt].next=head[u];
head[u]=cnt;
}
void AddTree(int u,int v) {
tree[++cnt].v=v;
tree[cnt].next=head[u];
head[u]=cnt;
}
struct node {
int id,dis;
inline node(int x,int y) {
id=x,dis=y;
}
inline bool operator < (const node b) const {
return dis>b.dis;
}
};
priority_queue<node> Q;
int dis[Size];
void Dijkstra(int s) {
memset(dis,0x3f,sizeof(dis));
dis[s]=0;
Q.push(node(s,0));
while(!Q.empty()) {
node now=Q.top(); Q.pop();
int x=now.id,d=now.dis;
if(d!=dis[x]) continue;
for(re i=head[x]; i; i=w[i].next) {
int nxt=w[i].v;
if(dis[x]+w[i].t<dis[nxt]) {
dis[nxt]=dis[x]+w[i].t;
Q.push(node(nxt,dis[nxt]));
}
}
}
}
int father[Size],val[Size];
int Find(int x) {
if(x==father[x]) return x;
return father[x]=Find(father[x]);
}
inline bool comp(Edge jzm,Edge xjp) {
return jzm.h>xjp.h;
}
void Kruskal() {
sort(w+1,w+1+cnt,comp);
int maxn=n<<1,all=cnt,tot=n;
for(re i=1; i<=maxn; i++) father[i]=i;
memset(head,0,sizeof(head)); cnt=0;
for(re i=1; i<=all; i++) {
int fu=Find(w[i].u);
int fv=Find(w[i].v);
if(fu!=fv) {
father[fu]=father[fv]=++tot;
AddTree(tot,fu);
AddTree(tot,fv);
val[tot]=w[i].h;
if(tot+1==maxn) return;
}
}
}
int deep[Size],anc[Size][21];
void dfs(int x,int fa) {
deep[x]=deep[fa]+1;
anc[x][0]=fa;
for(re i=1; i<=18; i++) {
anc[x][i]=anc[anc[x][i-1]][i-1];
}
for(int i=head[x]; i; i=tree[i].next) {
int nxt=tree[i].v;
if(nxt!=fa) {
dfs(nxt,x);
if(dis[nxt]<dis[x]) {
dis[x]=dis[nxt];
}
}
}
}
int Query(int x,int p) {
for(re i=18; i>=0; i--) {
if(deep[anc[x][i]]>=0 && val[anc[x][i]]>p) {
x=anc[x][i];
}
}
return dis[x];
}
void Fujibayashi_Ryou() {
int T=read();
while(T--) {
memset(head,0,sizeof(head)); cnt=0;
n=read();
m=read();
for(re i=1; i<=m; i++) {
int u=read();
int v=read();
int t=read();
int h=read();
AddEdge(u,v,h,t);
AddEdge(v,u,h,t);
}
q=read();
k=read();
s=read();
Dijkstra(1);
Kruskal();
dfs((n<<1)-1,0);
int lastans=0;
while(q--) {
int v=(read()+k*lastans-1)%n+1;
int p=(read()+k*lastans)%(s+1);
printf("%d\n",lastans=Query(v,p));
}
}
}
}
int main() {
I_Love::Fujibayashi_Ryou();
return 0;
}