NOI2018 Day1 归程(Kruskal重构树)

    • 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 
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%10+'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 pairint>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_queuevector

,greater

>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); } } }

你可能感兴趣的:(杂~)