[NOI2018] 归程

P4768 [NOI2018] 归程

题目描述

本题的故事发生在魔力之都,在这里我们将为你介绍一些必要的设定。

魔力之都可以抽象成一个 \(n\) 个节点、\(m\) 条边的无向连通图(节点的编号从 \(1\)\(n\))。我们依次用 \(l,a\) 描述一条边的长度、海拔

作为季风气候的代表城市,魔力之都时常有雨水相伴,因此道路积水总是不可避免的。由于整个城市的排水系统连通,因此有积水的边一定是海拔相对最低的一些边。我们用水位线来描述降雨的程度,它的意义是:所有海拔不超过水位线的边都是有积水的。

Yazid 是一名来自魔力之都的 OIer,刚参加完 ION2018 的他将踏上归程,回到他温暖的家。Yazid 的家恰好在魔力之都的 \(1\) 号节点。对于接下来 \(Q\) 天,每一天 Yazid 都会告诉你他的出发点 \(v\) ,以及当天的水位线 \(p\)

每一天,Yazid 在出发点都拥有一辆车。这辆车由于一些故障不能经过有积水的边。Yazid 可以在任意节点下车,这样接下来他就可以步行经过有积水的边。但车会被留在他下车的节点并不会再被使用。
需要特殊说明的是,第二天车会被重置,这意味着:

  • 车会在新的出发点被准备好。
  • Yazid 不能利用之前在某处停放的车。

Yazid 非常讨厌在雨天步行,因此他希望在完成回家这一目标的同时,最小化他步行经过的边的总长度。请你帮助 Yazid 进行计算。

数据范围与约定

所有测试点均保证 \(T\leq 3\),所有测试点中的所有数据均满足如下限制:

  • \(n\leq 2\times 10^5\)\(m\leq 4\times 10^5\)\(Q\leq 4\times 10^5\)\(K\in\left\{0,1\right\}\)\(1\leq S\leq 10^9\)

  • 对于所有边:\(l\leq 10^4\)\(a\leq 10^9\)

  • 任意两点之间都直接或间接通过边相连。

  • 强制在线

Solution:

kruskal 重构树魅力时刻。

其实如果写过 P4197 Peaks 的话那么这题几乎是纯送的。

先分析题意:

我们先求出原图上以1为起点的单源最短路,然后题目要求我们在一个联通图上求出从一个点 \(u\) 出发只经过满足 $ h > p$ 的边能到达的所有节点 \(v\)\(dis_{v}\) 的最小值。

实现:

我们发现 $ h > p$ 这个条件能通过kruskal重构树来构造.我们建一颗以 \(h\) 构成小根堆的kruskal重构树,叶子节点存的是 \(dis\) 然后对于每次查询,我们从节点 \(u\) 一直倍增向上跳到满足$ h > p$且深度最小的节点 \(u'\) 然后答案就是节点 \(u'\) 子树下的 \(dis\) 的最小值。

至于如何查询 \(u'\) 的子树,这里我选的是在欧拉序上查 st表

Code:

#include<bits/stdc++.h>
const int N=4e5+5;
const int inf=1e9;
const int lg=20;
using namespace std;
int n,m,days,ans;
vector<tuple<int,int> > E[N];
vector<int> e[N<<1];
int val[N],dis[N];
struct Edge{
    int x,y,w;
    bool operator <(const Edge &e)const{
        return w>e.w;
    }
}q[N];
struct Kruskal{
    int fa[N],tot;
    int find(int x){return fa[x]= fa[x]==x ? fa[x] : find(fa[x]);}
    void add(int x,int y){e[x].emplace_back(y);}
    void build()
    {
        tot=n;
        for(int u=1;u<=n;u++)fa[u]=u;
        for(int i=1;i<=m;i++)
        {
            int x=q[i].x,y=q[i].y,w=q[i].w;
            int u=find(x),v=find(y);
            if(u!=v)
            {
                val[++tot]=w;
                add(tot,v);add(tot,u);
                //cout<<"add:"<<tot<<" : "<<u<<" "<<v<<"="<<w<<"\n";
                fa[tot]=fa[u]=fa[v]=tot;
            }
        }
    }

}K;
struct Dijkstra{
    struct Node{
        int x,val;
        bool operator<(const Node &n)const{
            return n.val<val;
        }
    };
    priority_queue<Node> Q;
    int vis[N];
    void init()
    {
        for(int i=1;i<=n;i++)dis[i]=inf,vis[i]=0;
    }
    void dijksta(int s)
    {
        init();
        dis[s]=0;Q.push({s,dis[s]});
        while(!Q.empty())
        {
            int x=Q.top().x;Q.pop();
            if(vis[x])continue;
            vis[x]=1;
            for(auto [y,w] : E[x])
            {
                if(dis[y]>dis[x]+w)
                {
                    dis[y]=dis[x]+w;
                    Q.push({y,dis[y]});
                }
            }
        }
    }
}D;
struct Graph{
    int dfn[N<<1];
    int f[N<<1][lg+5];
    int st[N<<1],ed[N<<1];
    void dfs(int x,int fa)
    {
        st[x]=++dfn[0];
        f[x][0]=fa;
        for(int j=1;j<=lg;j++)f[x][j]=f[f[x][j-1]][j-1];
        for(auto y : e[x])
        {
            if(y==fa)continue;
            dfs(y,x);
        }
        ed[x]=dfn[0];
    }
    int find(int x,int k)
    {
        for(int j=lg;j>=0;j--)if(val[f[x][j]]>k)x=f[x][j];
        return x;
    }
}G;
struct ST{
    int LG[N<<1];
    int st[N<<1][lg+5];
    int R;
    void init()
    {
        R=(n<<1)-1;
        for(int i=2;i<=R;i++)LG[i]=LG[i>>1]+1;
        for(int i=1;i<=R;i++)st[i][0]=inf;
        for(int i=1;i<=n;i++)st[G.st[i]][0]=dis[i];
    }
    void build()
    {
        init();
        //cout<<"R:"<<R<<"\n";
        //for(int i=1;i<=R;i++)cout<<st[i][0]<<(i==R ? "\n" : " ");
        for(int j=1;j<=lg;j++)for(int i=1;i<=R;i++)
        {
            int tmp=min(i+(1<<j-1),R);
            st[i][j]=min(st[i][j-1],st[tmp][j-1]);
        }
    }
    int query(int l,int r)
    {
        int k=LG[r-l+1];
        return min(st[l][k],st[r-(1<<k)+1][k]);
    }
}S;
struct Change{
    int k,s;
    int chage_v(int x){return (x+k*ans-1)%n+1;}
    int chage_p(int x){return (x+k*ans)%(s+1);}
}C;
void Clear()
{
    int R=(n<<1)-1;G.dfn[0]=0;
    for(int i=1;i<=n;i++)E[i].clear();
    for(int i=1;i<=R;i++)e[i].clear(),val[i];
}
void work()
{
    cin>>n>>m;
    ans=0;
    for(int i=1,x,y,w,h;i<=m;i++)
    {
        scanf("%d%d%d%d",&x,&y,&w,&h);
        E[x].emplace_back(y,w);
        E[y].emplace_back(x,w);
        q[i]={x,y,h};
    }
    sort(q+1,q+1+m);
    D.dijksta(1);
    K.build();
    G.dfs(K.tot,0);
    S.build();
    cin>>days>>C.k>>C.s;
    for(int i=1,v,p;i<=days;i++)
    {
        scanf("%d%d",&v,&p);
        v=C.chage_v(v);p=C.chage_p(p);
        //cout<<"v p : "<<v<<" "<<p<<"\n";
        v=G.find(v,p);
        ans=S.query(G.st[v],G.ed[v]);
        //cout<<v<<"="<<G.st[v]<<" "<<G.ed[v]<<"\n";
        printf("%d\n",ans);
    }
    //cout<<"END\n";
    Clear();
}
int main()
{
    //freopen("P4768_2.in","r",stdin);freopen("P4768.out","w",stdout);
    int T;
    cin>>T;
    while(T--)
    work();
    return 0;
}
posted @ 2024-12-27 19:21  liuboom  阅读(22)  评论(0)    收藏  举报