题意:给你一张图,图中有m条边,每条边有长度和一个海拔值,给你q次询问,每次给你一个节点v和一个海拔值p,问你从v到1的最短距离是多少,对于图中的边如果海拔值小于p,那边的长度在这次查询时就会变为0;
题解:首先对于海拔大于o,那边连接的点就相当于一个点,那对于一个联通块来说,联通块中的所有点到1的最短距离就是就是最短距离对应的那个点,所以我们需要维护一个并查集,然后考虑对于每次海拔的更新,我们所对应的边也会被更新。所以考虑以海拔值做时间,海拔值相同的边对应的时间相同,我们每次询问是只需要访问p对应的当前版本中包含v的联通块到1的最小距离就好了。对于主席树维护的持久化并查集在合并父亲节点时需要按秩归并,而不能用最短路径当做主席树的秩。至于最短路用dij求出,SPFA已经死了
AC代码:
#include<stdio.h>
#include<algorithm>
#include<string.h>
#include<queue>
#include<vector>
#include<iostream>
//#pragma comment(linker, "/STACK:102400000,102400000")
using namespace std;
const int maxn=2e5+5;
const int inf=0x3f3f3f3f;
struct edge
{
int next, ed, len;
};
edge e[maxn*20];
int p[maxn], cnt;
void add_edge(int st,int ed,int len)
{
e[cnt].ed=ed;
e[cnt].next=p[st];
e[cnt].len=len;
p[st]=cnt++;
}
int read(){
int x=0,w=1;char ch=getchar();
while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
if(ch=='-')w=0,ch=getchar();
while(ch>='0'&&ch<='9')x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
return w?x:-x;
}
struct qnode{
int v,c;
qnode(int _v=0,int _c=0):v(_v),c(_c){}
bool operator < (const qnode &r) const {
return c>r.c;
}
};
bool vis[maxn];
int dist[maxn],father[maxn];
priority_queue<qnode> que;
void dijkstra(int n){
memset(vis,false,sizeof(vis));
for(int a=1;a<=n;a++)
dist[a]=inf,father[a]=a;
dist[1]=0;
que.push(qnode{1,0});
qnode tmp;
while(!que.empty()){
tmp=que.top();
que.pop();
int u=tmp.v;
if(vis[u])
continue;
vis[u]=true;
for(int a=p[u];a!=-1;a=e[a].next){
int v=e[a].ed;
int cost=e[a].len;
if(!vis[v]&&dist[v]>dist[u]+cost){
dist[v]=dist[u]+cost;
que.push(qnode(v,dist[v]));
}
}
}
}
struct node{
int lson,rson,fa;
int level;
};
node tree[maxn*40];
struct node1{
int u,v;
int a;
};
node1 side[2*maxn];
bool cmp(node1 a,node1 b){
if(a.a<b.a)
return true;
return false;
}
int sea[maxn*2];
int tj,mn[maxn*40];
int ti[maxn*2];
int find1(int x){
if(x==father[x])
return x;
return father[x]=find1(father[x]);
}
void build(int &now,int l,int r){
now=++tj;
if(l==r){
tree[now].fa=l;
tree[now].level=dist[l];
mn[now]=dist[l];
return ;
}
int mid=(l+r)>>1;
build(tree[now].lson,l,mid);
build(tree[now].rson,mid+1,r);
}
int getfa(int now1,int x,int n){
int now;
int l,r;
while(1){
l=1,r=n;
now=now1;
while(l!=r){
int mid=(l+r)>>1;
if(mid>=x){
r=mid;
now=tree[now].lson;
}
else{
l=mid+1;
now=tree[now].rson;
}
}
if(x==tree[now].fa)
return now;
x=tree[now].fa;
}
}
int add(int *now,int lst,int l,int r,int x){
while(l!=r){
*now=++tj;
int mid=(l+r)>>1;
tree[*now].lson=tree[lst].lson;
tree[*now].rson=tree[lst].rson;
if(x<=mid){
lst=tree[lst].lson;
r=mid;
now=&(tree[*now].lson);
}
else{
lst=tree[lst].rson;
l=mid+1;
now=&(tree[*now].rson);
}
}
return *now=++tj;
}
inline void work(int now,int x,int y,int n){
int fx=find1(x),fy=find1(y);
if(fx==fy)
return ;
fx=getfa(ti[now],x,n),fy=getfa(ti[now],y,n);
if(tree[fx].level>tree[fy].level)
swap(fx,fy);
father[tree[fx].fa]=tree[fy].fa;
tree[add(&ti[now],ti[now],1,n,tree[fx].fa)].fa=tree[fy].fa;
int w=add(&ti[now],ti[now],1,n,tree[fy].fa);
tree[w].fa=tree[fy].fa;
mn[w]=min(mn[fx],mn[fy]);
tree[w].level=tree[fy].level+(tree[fx].level==tree[fx].level);
//printf("*\n");
//printf("%d\n",getfa(ti[now],3,n));
}
int main( )
{
int t,n,m;
t=read();
while(t--){
n=read(),m=read();
int u,v,l,a;
cnt=0;
memset(p,-1,sizeof(p));
for(int i=1;i<=m;i++){
u=read(),v=read(),l=read(),a=read();
add_edge(u,v,l);
add_edge(v,u,l);
side[i]={u,v,a};
sea[i]=a;
}
dijkstra(n);
int q,k1,s,v1,p;
q=read(),k1=read(),s=read();
sort(side+1,side+m+1,cmp);
for(int i=1;i<=m;i++)
sea[i]=side[i].a;
sea[m+1]=s+1;
int num=unique(sea+1,sea+m+2)-sea-1;
tj=0;
build(ti[num],1,n);
for(int i=num-1,j=m;i;i--){
ti[i]=ti[i+1];
for(;j&&side[j].a==sea[i];j--){
work(i,side[j].u,side[j].v,n);
}
}
int lastans=0;
while(q--){
v1=(read()+k1*lastans-1)%n+1;
p=(read()+k1*lastans)%(s+1);
//printf("%d %d %d\n",v1,p,upper_bound(sea+1,sea+num+1,p));
lastans=mn[getfa(ti[upper_bound(sea+1,sea+num+1,p)-sea],v1,n)];
printf("%d\n",lastans);
}
}
}