Luogu4768 NOI2018归程(最短路径+kruskal重构树)
按海拔从大到小合并建出kruskal重构树,这样就能知道开车能到达哪些点,对这些点到1的最短路取min即可。最难的部分在于多组数据的初始化和数组大小的设置。
#include<iostream> #include<cstdio> #include<cmath> #include<cstdlib> #include<cstring> #include<algorithm> #include<queue> #include<cassert> using namespace std; #define ll long long #define N 200010 #define M 400010 #define inf 2000000010 char getc(){char c=getchar();while ((c<'A'||c>'Z')&&(c<'a'||c>'z')&&(c<'0'||c>'9')) c=getchar();return c;} int gcd(int n,int m){return m==0?n:gcd(m,n%m);} int read() { int x=0,f=1;char c=getchar(); while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();} while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar(); return x*f; } int T,n,m,p[N],d[N],fa[N<<1],t,cnt; bool flag[N]; struct data{int to,nxt,len,h; }edge[M<<1]; void addedge(int x,int y,int z,int h){t++;edge[t].to=y,edge[t].nxt=p[x],edge[t].len=z,edge[t].h=h,p[x]=t;} struct data2 { int x,d; bool operator <(const data2&a) const { return d>a.d; } }; struct data3 { int x,y,z; bool operator <(const data3&a) const { return z>a.z; } }e[M]; priority_queue<data2> q; int find(int x){return fa[x]==x?x:fa[x]=find(fa[x]);} void dijkstra() { while (!q.empty()) q.pop();q.push((data2){1,0}); for (int i=2;i<=n;i++) d[i]=inf;d[1]=0; memset(flag,0,sizeof(flag)); for (;;) { while (!q.empty()&&flag[q.top().x]) q.pop(); if (q.empty()) break; data2 x=q.top();q.pop(); flag[x.x]=1; for (int i=p[x.x];i;i=edge[i].nxt) if (x.d+edge[i].len<d[edge[i].to]) { d[edge[i].to]=x.d+edge[i].len; q.push((data2){edge[i].to,d[edge[i].to]}); } } } namespace kruskal_tree { int p[N<<1],t,fa[N<<1][20],val[N<<1],h[N<<1]; struct data{int to,nxt,len;}edge[N<<1]; void addedge(int x,int y){t++;edge[t].to=y,edge[t].nxt=p[x],p[x]=t;} void dfs(int k) { val[k]=k<=n?d[k]:inf; for (int i=p[k];i;i=edge[i].nxt) { fa[edge[i].to][0]=k; dfs(edge[i].to); val[k]=min(val[k],val[edge[i].to]); } } void build() { fa[cnt][0]=cnt;dfs(cnt); for (int j=1;j<20;j++) for (int i=1;i<=cnt;i++) fa[i][j]=fa[fa[i][j-1]][j-1]; } } int main() { #ifndef ONLINE_JUDGE freopen("return.in","r",stdin); freopen("return.out","w",stdout); const char LL[]="%I64d\n"; #else const char LL[]="%lld\n"; #endif T=read(); while (T--) { n=read(),m=read(); for (int i=1;i<=n;i++) p[i]=0;t=0; for (int i=1;i<=m;i++) { int x=read(),y=read(),z=read(),h=read(); e[i].x=x,e[i].y=y,e[i].z=h; addedge(x,y,z,h),addedge(y,x,z,h); } dijkstra(); sort(e+1,e+m+1); for (int i=1;i<=n;i++) fa[i]=i,kruskal_tree::h[i]=inf,kruskal_tree::p[i]=0;cnt=n;kruskal_tree::t=0; for (int i=1;i<=m;i++) { int p=find(e[i].x),q=find(e[i].y); if (p!=q) { cnt++;fa[cnt]=fa[p]=fa[q]=cnt;kruskal_tree::p[cnt]=0; kruskal_tree::addedge(cnt,p),kruskal_tree::addedge(cnt,q); kruskal_tree::h[cnt]=e[i].z; } } kruskal_tree::build(); int Q=read(),K=read(),S=read(),ans=0; while (Q--) { int x=(read()+K*ans-1)%n+1,y=(read()+K*ans)%(S+1); for (int j=19;~j;j--) if (kruskal_tree::h[kruskal_tree::fa[x][j]]>y) x=kruskal_tree::fa[x][j]; printf("%d\n",ans=kruskal_tree::val[x]); } } return 0; }