NOI2018d1t1 归程 (dijkstra+kruskal重构树)

时间:2022-07-28 20:04:26

题意:给一张无向联通图,每条边有长度和高度,每次询问在高度大于p的边,从v点能到达的所有点到1号点的最短距离(强制在线)

首先dijkstra求出每个点到1号点的距离

易知:如果我按高度从高到低给边排序然后用kruskal的方法做出一棵生成树,那么在高度大于p的条件下,在原图中联通的两点在生成树中依旧联通

于是就可以在做kruskal的时候建一个叫做重构树的东西,在用并查集维护联通块的同时维护一个树结构:

  对于每条边,若原本两端点u,v不连通,则新建一个节点t,设a,b为u,v在并查集中的祖先,令并查集和树结构中fa[a]=fa[b]=t,同时记下树中t的两个孩子为a,b,以及t的高度与边的高度相同

这样,树中的每棵子树的叶节点都是连通的,并且树中深度越深,节点对应边的高度就越大

dfs一下就可以处理出每个子树对应联通块的距1号点的最近距离。

然后对于点v,就可以倍增找出高度恰大于p的那个节点,就是最后结果

 #include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#include<vector>
#define LL long long int
#define pa pair<int,int>
using namespace std;
const int maxn=2e5+,logn=,maxm=4e5+,inf=0x3f3f3f3f; int rd(){
int x=;char c=getchar();
while(c<''||c>'') c=getchar();
while(c>=''&&c<='') x=x*+c-'',c=getchar();
return x;
} struct Edge{
int a,b,l,h,ne;
}eg[maxm*];
struct Node{
int fa[logn],v,h,ch[];
}tr[maxn*];
int bcj[maxn*],tct;
int N,M,Q,K,S;
int egh[maxn],ect;
int dis[maxn];
priority_queue<pa,vector<pa>,greater<pa> > q; inline void adeg(int a,int b,int l,int h){
eg[ect].a=a;eg[ect].b=b;eg[ect].l=l;eg[ect].h=h;eg[ect].ne=egh[a];egh[a]=ect++;
} void dijkstra(){
memset(dis,,sizeof(dis));dis[]=;
q.push(make_pair(,));
while(!q.empty()){
int p=q.top().second;q.pop();
for(int i=egh[p];i!=-;i=eg[i].ne){
int b=eg[i].b;
if(dis[b]>dis[p]+eg[i].l){
dis[b]=dis[p]+eg[i].l;
q.push(make_pair(dis[b],b));
}
}
}
} int getf(int x){return x==bcj[x]?x:bcj[x]=getf(bcj[x]);} void kruskal(){
memset(tr,,sizeof(tr));
for(int i=;i<=N*;i++) bcj[i]=i,tr[i].v=inf;tct=N;
for(int i=,n=;i<ect&&n<N;i++){
int a=getf(eg[i].a),b=getf(eg[i].b);
if(a==b) continue;
bcj[a]=bcj[b]=++tct;
tr[a].fa[]=tr[b].fa[]=tct;
tr[tct].ch[]=a;tr[tct].ch[]=b;
tr[tct].h=eg[i].h;n++;
}
} void dfs(int x){
for(int i=;i<logn-;i++){
if(!tr[tr[x].fa[i]].fa[i]) break;
tr[x].fa[i+]=tr[tr[x].fa[i]].fa[i];
}
if(tr[x].ch[]){
dfs(tr[x].ch[]);dfs(tr[x].ch[]);
tr[x].v=min(tr[tr[x].ch[]].v,tr[tr[x].ch[]].v);
}else tr[x].v=dis[x];
} inline bool cmp(Edge a,Edge b){
return a.h>b.h;
} int query(int v,int p){
for(int i=logn-;i>=;i--){
if(tr[v].fa[i]&&tr[tr[v].fa[i]].h>p) v=tr[v].fa[i];
}return tr[v].v;
} int main(){
int i,j,k;
//freopen("return.in","r",stdin);
for(int T=rd();T;T--){
N=rd(),M=rd();memset(egh,-,sizeof(egh));ect=;
for(i=;i<=M;i++){
int a=rd(),b=rd(),c=rd(),d=rd();
adeg(a,b,c,d);adeg(b,a,c,d);
}dijkstra();
sort(eg,eg+ect,cmp);kruskal();dfs(tct);
Q=rd(),K=rd(),S=rd();
int lastans=;
for(i=;i<=Q;i++){
int v=(rd()+K*lastans-)%N+;
int p=(rd()+K*lastans)%(S+);
printf("%d\n",lastans=query(v,p));
}
}
}