zoukankan      html  css  js  c++  java
  • NOI2018 Day1 归程(Kruskal重构树)

    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%10+'0');}
    template<class T>inline void writeln(T x){if(x<0)putchar('-');x=abs(x);print(x);putchar('
    ');}
    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
    ",ans);
            }
        }
    }
    
    「我不敢下苦功琢磨自己,怕终于知道自己并非珠玉;然而心中既存着一丝希冀,便又不肯甘心与瓦砾为伍。」
  • 相关阅读:
    前端面试攻略1------算法部分
    MongoDB学习
    MongoDB作为Windows服务来安装 错误1053:服务没有及时响应启动或控制请求
    Vue 入门之 Vuex 实战
    Vue 路由详解
    vue入门全局配置
    VSCode配合ESLint自动修复格式化
    vue入门之单文件组件
    Echarts图表-学习
    GoJS学习
  • 原文地址:https://www.cnblogs.com/Apocrypha/p/9430500.html
Copyright © 2011-2022 走看看