神奇的kruskal重构树(考场不会可以现场发明)。。。
首先跑一遍dj,则对于每次询问,答案就是v能到的所有点中dis最小的点的dis
考虑按海拔高度,从大到小加边直到图联通,我们需要维护每个点所在的连通块,以及每个连通块中dis最小的点
离线。。。并查集?
强制在线。。。可持久化并查集?
有没有更优秀的做法?我们可以用kruskal重构树。
对于加入的一条边(u,v),我们找到u和v所在树的根节点x和y,新建一个节点new并把x和y的父亲设为new,new的点权则是新加入边的边权
这样一个点u走海拔超过d的边能到的点就是其经过点权超过d的点能到的点,我们发现父亲的点权总是小于儿子,因此我们倍增找到u能到的深度最浅的祖先v,u能到的所有点就是v的子树
#include<bits/stdc++.h> #define file(s) freopen(s".in","r",stdin);freopen(s".out","w",stdout); #define P 998244353 #define mid (l+r>>1) #define N 1100000 #define lb(x) (x&(-x)) #define inf 999999999 #define M 1658561 #define ll long long #define mem(x) memset(x,0,sizeof(x)); using namespace std; int dis[N],f[N][21],ls,cnt,tot,n,m,T,Q,k,s,fa[N],to[N],nxt[N],head[N],w[N],mi[N],vis[N],p,d[N],v; struct edge{int x,y,w,d;}e[N]; struct node{ int id,dis; friend bool operator <(node x,node y){return x.dis>y.dis;} }; priority_queue<node>q; bool cmp(edge x,edge y){ return x.d>y.d;} int find(int x){ return fa[x]==x? x:fa[x]=find(fa[x]);} void add(int x,int y,int z){ // printf("%d %d %d ",x,y,z); to[++cnt]=y; nxt[cnt]=head[x]; head[x]=cnt; w[cnt]=z; } int dfs2(int x){ // printf("%d %d ",x,dis[x]); mi[x]=dis[x]; for(int i=head[x];i;i=nxt[i])mi[x]=min(mi[x],dfs2(to[i])); return mi[x]; } void dj(){ memset(dis,0x3f,sizeof(dis)); mem(vis); q.push({1,0});dis[1]=0; while(!q.empty()){ int x = q.top().id;q.pop(); if(vis[x]) continue; vis[x] = 1; for(int i=head[x];i;i=nxt[i]){ if(dis[to[i]]>dis[x]+w[i]){ dis[to[i]]=dis[x]+w[i]; q.push({to[i],dis[to[i]]}); } } } } int main(){ //file("s"); scanf("%d",&T); while(T--){ mem(head);mem(d);ls=cnt=0; scanf("%d%d",&n,&m); for(int i=1;i<=m;i++) scanf("%d%d%d%d",&e[i].x,&e[i].y,&e[i].w,&e[i].d),add(e[i].x,e[i].y,e[i].w),add(e[i].y,e[i].x,e[i].w); dj(); mem(head);cnt=0; scanf("%d%d%d",&Q,&k,&s); sort(e+1,e+m+1,cmp);tot=n; for(int i=1;i<=n;i++) fa[i]=i; for(int i=1;i<=m&&tot-n<n-1;i++){ int x=find(e[i].x),y=find(e[i].y); // printf("/%d %d/ ",x,y); if(x==y) continue; // printf("-%d %d- ",x,y); d[++tot]=e[i].d; fa[tot]=tot; add(tot,x,0);add(tot,y,0); fa[x]=f[x][0]=fa[y]=f[y][0]=tot; } for(int i=1;i<=20;i++) for(int j=1;j<=tot;j++) f[j][i]=f[f[j][i-1]][i-1]; //printf("%d ",tot); dfs2(tot); //return 0; for(int i=1;i<=Q;i++){ scanf("%d%d",&v,&p); v=(v+k*ls-1)%n+1;p=(p+k*ls)%(s+1); for(int i=20;~i;i--) if(d[f[v][i]]>p)v=f[v][i]; printf("%d ",ls=mi[v]); } } return 0; }