NOI2018 Day1 归程(Kruskal重构树)

mac2022-06-30  135

目录

NOI2018 Day1 return 题解AC代码:

NOI2018 Day1 return

题解

作为NOI Day1 的T1,这道题目还是比较清真的(虽然自己在同步赛的时候只打了70分的部分分,然后数组开小了挂成了55分。。)正解的方法似乎有很多,可持久化并查集什么的都可以做。但个人认为还是Kruskal重构树的方法比较好些,也比较容易一点。 Kruskal重构树的基础还是像Kruskal生成树一样,先把边sort,再一条一条加进生成树中。而重构树唯一不同的点是当重构树在进行两个联通块合并的时候,并不是直接将其合并,而是新建一个父节点,其点权为当前枚举到的边的边权。这样显然的Kruskal重构树就会有两个比较重要的性质了: ①这颗重构树是个二叉树(虽然在这里并没有什么用) ②这棵树是个大(小)根堆 知道了这一点我们就可以开始做这道题了。我们先按海拔从大到小将每条边的排序,然后做Kruskal重构树,这样我们生成的Kruskal重构树就是一棵以海拔为关键字的小根堆,同时他会有一些性质:如果一条边被水淹没了(在重构树中就是那条边所对应的点),那么这个节点的所有父节点都会被水淹没,并且如果这条边没有被水淹没,那么它的子树的任意一个点也不会被水淹没,于是这棵子树的任意两个点都可以通过开车到达。于是我们就可以先跑一边最短路(出题人:SPFA死掉了),然后在进行构造Kruskal重构树的时候维护子树中到根的最短距离Mn。对于每一个询问,我们只需要倍增在重构树上找到未被水淹没的深度最浅的节点,然后返回这个节点的Mn的值就行了,还是比较好写的。

AC代码:

#pragma GCC optimize (2) #include <bits/stdc++.h> using namespace std; typedef long long ll; bool Finish_read; template<class T>inline void read(T &x){Finish_read=0;x=0;int f=1;char ch=getchar();while(!isdigit(ch)){if(ch=='-')f=-1;if(ch==EOF)return;ch=getchar();}while(isdigit(ch))x=x*10+ch-'0',ch=getchar();x*=f;Finish_read=1;} template<class T>inline void print(T x){if(x/10!=0)print(x/10);putchar(x+'0');} template<class T>inline void writeln(T x){if(x<0)putchar('-');x=abs(x);print(x);putchar('\n');} template<class T>inline void write(T x){if(x<0)putchar('-');x=abs(x);print(x);} /*================Header Template==============*/ const int maxn=4e5+500; typedef pair<ll,int>P; #define fi first #define se second int n,m,T,tot,waytot,ndcnt,Q,k,s,cnt; ll ans; int head[maxn],fa[maxn<<1],val[maxn<<1],Head[maxn<<1],deep[maxn<<1],p[maxn][22]; ll dis[maxn],Mn[maxn<<1]; bool vis[maxn]; struct edge { int to,nxt,l,h; }E[maxn<<2]; struct sortedge { int f,t,l,h; bool operator < (const sortedge &rhs) const { return h>rhs.h; } }EE[maxn<<2]; struct way { int to,nxt; }G[maxn<<4]; /*==================Define Area================*/ void FO() { freopen("return.in","r",stdin); freopen("return.out","w",stdout); } namespace doit { void init() { ans=tot=waytot=cnt=0; memset(head,-1,sizeof head); memset(Head,-1,sizeof Head); for(int i=1;i<=200000;i++) { fa[i]=i; } } void addedge(int u,int v,int h,int l) { E[++tot].to=v;E[tot].nxt=head[u];head[u]=tot;E[tot].h=h;E[tot].l=l; E[++tot].to=u;E[tot].nxt=head[v];head[v]=tot;E[tot].h=h;E[tot].l=l; } void Dj() { priority_queue<P,vector<P>,greater<P> >Q; while(!Q.empty()) Q.pop(); memset(vis,0,sizeof vis); memset(dis,0x7f,sizeof dis); dis[1]=0; Q.push(P(dis[1],1)); while(!Q.empty()) { P p=Q.top();Q.pop(); int idx=p.se; ll dist=p.fi; vis[idx]=1; for(int i=head[idx];~i;i=E[i].nxt) { int to=E[i].to; if(vis[to]) continue; if(dis[to]>dist+E[i].l) { dis[to]=dist+E[i].l; Q.push(P(dis[to],to)); } } } } } namespace KruskalTree { void addway(int u,int v) { G[++waytot].to=v;G[waytot].nxt=Head[u];Head[u]=waytot; G[++waytot].to=u;G[waytot].nxt=Head[v];Head[v]=waytot; } int find(int x) { return fa[x]==x?x:fa[x]=find(fa[x]); } void unite(int x,int y,int v) { int fx=find(x),fy=find(y); if(fx==fy) return ; ++ndcnt; addway(fx,ndcnt); addway(fy,ndcnt); Mn[ndcnt]=min(Mn[fx],Mn[fy]); fa[ndcnt]=ndcnt; fa[fx]=ndcnt; fa[fy]=ndcnt; val[ndcnt]=v; return ; } void Kruskal() { ndcnt=n; for(int i=1;i<=n;i++) { Mn[i]=dis[i]; } for(int i=1;i<=cnt;i++) { unite(EE[i].f,EE[i].t,EE[i].h); } } } namespace LCA { void dfs(int o,int ff,int dep) { deep[o]=dep; p[o][0]=ff; for(int i=Head[o];~i;i=G[i].nxt) { int to=G[i].to; if(to==ff) continue; dfs(to,o,dep+1); } } void Cal() { for(int i=1;i<=20;i++) { for(int j=1;j<=ndcnt;j++) { p[j][i]=p[p[j][i-1]][i-1]; } } } int Solve(ll o,ll a) { for(int i=20;i>=0;i--) { if(p[o][i]&&val[p[o][i]]>a) o=p[o][i]; } return o; } } using namespace doit; using namespace KruskalTree; using namespace LCA; int main() { FO(); read(T); while(T--) { init(); read(n);read(m); for(int i=1,u,v,h,l;i<=m;i++) { read(u);read(v);read(l);read(h); addedge(u,v,h,l); EE[++cnt].f=u;EE[cnt].t=v;EE[cnt].l=l;EE[cnt].h=h; } Dj(); sort(EE+1,EE+1+cnt); Kruskal(); dfs(ndcnt,0,1); Cal(); read(Q);read(k);read(s); while(Q--) { ll v,p; read(v);read(p); v=(v+k*ans-1)%n+1; p=(p+k*ans)%(s+1); int o=Solve(v,p); ans=Mn[o]; printf("%lld\n",ans); } } }

转载于:https://www.cnblogs.com/Apocrypha/p/9430500.html

相关资源:JAVA上百实例源码以及开源项目
最新回复(0)