• 【NOI2018】归程 题解(kruskal重构树+最短路)


    题目链接

    题目大意:给定一张$n$个点$m$条边的无向图。每条边有长度和海拔。有$Q$次询问,每次给定起点$v$和当天水位线$p$,每次终点都是$1$。人可以选择坐车或走路,车只能在海拔大于水位线的路上跑。问人步行的最小距离。

    ----------------------------------

    我们可以转化一下题意:在$v$到$1$的路径上寻找断点$u$,使得从$v$到$u$的路径上车都可以跑,且从$u$到$1$步行的路径是满足前置条件的最短的一条路。

    显然从$v$开车出发可以到达的点路径的海拔都是大于水位线的。

    于是我们可以用$kruskal$重构树求解。(虽然我也不知道为什么用重构树,但是学姐讲课就是这么讲的

    我们将边以海拔作为关键字降序排序,构建一颗形如小根堆的$kruskal$重构树。对于每次询问我们找出树上深度最浅且海拔大于$p$的结点,由$kruskal$重构树的性质可知,它子树的所有结点都可由$v$开车到达。求解这个结点可以倍增解决,两行搞定。

    对于最短路,因为是无向边,我们可以预处理$1$的单源最短路径。然后对重构树进行$dfs$便可求出子树内的最短路。

    PS:关于$spfa$,它死了。

    时间复杂度$O(T(qlog n+n))$

    代码:

    #include<bits/stdc++.h>
    #define int long long
    using namespace std;
    const int maxn=2000005;
    int n,m,Q,T,K,S,val[maxn],tot,minn[maxn],f[maxn],fa[maxn][23],last;
    int head[maxn],cnt,dis[maxn],vis[maxn];
    struct edge{int next,to,dis;}edge[maxn];
    struct Node{int x,y,z;}a[maxn];
    struct node
    {
        int dis,pos;
        bool operator < (const node &x) const
        {
            return x.dis<dis;
        }
    };
    priority_queue<node> q;
    bool cmp(Node x,Node y){return x.z>y.z;}
    inline int read()
    {
        int x=0,f=1;char ch=getchar();
        while(!isdigit(ch)){if (ch=='-') f=-1;ch=getchar();}
        while(isdigit(ch)){x=x*10+ch-'0';ch=getchar();}
        return x*f;
    }
    inline void add(int from,int to,int dis)
    {
        edge[++cnt].next=head[from];
        edge[cnt].to=to;
        edge[cnt].dis=dis;
        head[from]=cnt;
    }
    inline void dijkstra()
    {
        memset(dis,0x3f,sizeof(dis));
        memset(vis,0,sizeof(vis));
        dis[1]=0;q.push((node){dis[1],1});
        while(!q.empty())
        {
            int now=q.top().pos;q.pop();
            if (vis[now]) continue;
            vis[now]=1;
            for (int i=head[now];i;i=edge[i].next)
            {
                int to=edge[i].to;
                if (dis[to]>dis[now]+edge[i].dis)
                {
                    dis[to]=dis[now]+edge[i].dis;
                    if (!vis[to]) q.push((node){dis[to],to});
                }
            }
        }
    }
    inline int find(int x)
    {
        if(x==f[x]) return x;
        return f[x]=find(f[x]);
    }
    inline void dfs(int now)
    {
        minn[now]=dis[now];
        for (int i=head[now];i;i=edge[i].next)
        {
            int to=edge[i].to;
            fa[to][0]=now;
            dfs(to);
            minn[now]=min(minn[now],minn[to]);
        }
    }
    inline void kruskal()
    {
        memset(head,0,sizeof(head));cnt=1;
        sort(a+1,a+m+1,cmp);
        for (int i=1;i<=n;i++) f[i]=i;
        for (int i=1;i<=m;i++)
        {
            int xx=find(a[i].x),yy=find(a[i].y);
            if (xx==yy) continue;
            val[++tot]=a[i].z;
            f[xx]=f[yy]=f[tot]=tot;
            add(tot,xx,0);add(tot,yy,0);
        }
        dfs(tot);
    }
    inline void clear()
    {
        memset(head,0,sizeof(head));cnt=1;
        memset(fa,0,sizeof(fa));
        memset(minn,0x3f,sizeof(minn));
    }
    signed main()
    {
        T=read();
        while(T--)
        {
            clear();
            n=read(),m=read();tot=n;last=0;
            for (int i=1;i<=m;i++)
            {
                int u=read(),v=read(),d=read(),h=read();
                add(u,v,d);add(v,u,d);
                a[i].x=u,a[i].y=v,a[i].z=h;
            }
            dijkstra();
            kruskal();
            for (int j=1;(1<<j)<=tot;j++)
                for (int i=1;i<=tot;i++)
                    fa[i][j]=fa[fa[i][j-1]][j-1];
            Q=read(),K=read(),S=read();
            while(Q--)
            {
                int v=read(),p=read();
                v=(v+K*last-1)%n+1;
                p=(p+K*last)%(S+1);
                for (int j=22;j>=0;--j)
                    if(fa[v][j]&&val[fa[v][j]]>p) v=fa[v][j];
                printf("%lld
    ",last=minn[v]); 
            }
        }
        return 0;
    }
  • 相关阅读:
    Windows Phone 8 Wallet 手机钱包 / 电子钱包
    Windows Phone 8 In app purchase 应用内购买 / 应用内支付
    Windows Phone 8 适应多屏分辨率
    Windows phone 8 基于定位的后台应用
    Windows Phone 8 Nokia地图控件
    Windows Phone 8 MDIL编译与代码混淆工具
    Windows Phone 8 近场通信 NFC / Bluetooth Proximity
    Windows Phone 8 镜头应用 Lenses for Windows Phone 8
    Windows Phone 8 与 windows 8 开发技术概览
    嵌入式成长轨迹54 【Zigbee项目】【CC2430基础实验】【系统睡眠工作状态】
  • 原文地址:https://www.cnblogs.com/Invictus-Ocean/p/13405763.html
Copyright © 2020-2023  润新知