LG P4768 [NOI2018] 归程

Description

本题的故事发生在魔力之都,在这里我们将为你介绍一些必要的设定。
魔力之都可以抽象成一个 $n$ 个节点、$m$ 条边的无向连通图(节点的编号从 $1$ 至 $n$)。我们依次用 $l,a$ 描述一条边的**长度、海拔**。

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

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

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

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

本题的部分测试点将强制在线,具体细节请见【输入格式】和【子任务】。

Solution

将边以海拔从高到低加入可持久化并查集,如果预处理出每个点到1的最短路,那么询问点连通块内最短路的最小值就是答案

查询时二分找到在哪个线段树上

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<queue>
using namespace std;
int n,m,head[200005],tot,sav[800005],T,q,K,S,dep[20000005],lc[20000005],rc[20000005],cnt,val[20000005],lasans,rt[800005];
unsigned int dist[200005],minn[20000005];
bool vst[200005];
struct Edge{
    int to,nxt;
    unsigned int w;
}edge[800005];
struct Node{
    int u,v,a;
    bool operator <(const Node &z)const{return a<z.a;}
}node[800005];
struct Ele{
    unsigned int x,val;
    bool operator <(const Ele &z)const{return val>z.val;}
};
inline int read(){
    int w=0,f=1;
    char ch=0;
    while(ch<'0'||ch>'9'){if(ch=='-') f=-1; ch=getchar();}
    while(ch>='0'&&ch<='9')w=(w<<1)+(w<<3)+ch-'0',ch=getchar();
    return w*f;
}
void dijkstra(int s){
    priority_queue<Ele>q;
    q.push((Ele){s,0});
    while(q.size()){
        Ele u=q.top();
        q.pop();
        if(vst[u.x])continue;
        dist[u.x]=u.val,vst[u.x]=true;
        for(int i=head[u.x];i;i=edge[i].nxt){
            int v=edge[i].to;
            if(!vst[v])q.push((Ele){v,edge[i].w+u.val});
        }
    }
}
void build(int &i,int l,int r){
    if(!i)i=++cnt;
    if(l==r){val[i]=l,minn[i]=dist[l];return;}
    int mid=l+r>>1;
    build(lc[i],l,mid),build(rc[i],mid+1,r);
}
int ask(int i,int l,int r,int p){
    if(l==r)return i;
    int mid=l+r>>1;
    if(p<=mid)return ask(lc[i],l,mid,p);
    else return ask(rc[i],mid+1,r,p);
}
int find(int i,int x){
    int ret=ask(i,1,n,x);
    while(val[ret]!=x)x=val[ret],ret=ask(i,1,n,x);
    return ret;
}
int update(int &i,int j,int l,int r,int p){
    i=++cnt;
    if(l==r)return i;
    int mid=l+r>>1;
    lc[i]=lc[j],rc[i]=rc[j];
    if(p<=mid)return update(lc[i],lc[j],l,mid,p);
    else return update(rc[i],rc[j],mid+1,r,p);
}
int main(){
    for(int t=read();t;t--){
        n=read(),m=read(),cnt=tot=lasans=0,memset(head,0,sizeof(head)),memset(rt,0,sizeof(rt)),memset(minn,0,sizeof(minn)),memset(dep,0,sizeof(dep)),memset(val,0,sizeof(val)),memset(vst,false,sizeof(vst)),memset(lc,0,sizeof(lc)),memset(rc,0,sizeof(rc));
        for(int i=1;i<=m;i++){
            int u=read(),v=read(),l=read(),a=read();
            edge[++tot]=(Edge){v,head[u],l},head[u]=tot,edge[++tot]=(Edge){u,head[v],l},head[v]=tot,node[i]=(Node){u,v,a};
        }
        dijkstra(1),q=read(),K=read(),S=read(),sort(node+1,node+m+1);
        for(int i=1;i<=m;i++)sav[i]=node[i].a;
        sav[m+1]=S+1,sort(sav+1,sav+m+2),T=unique(sav+1,sav+m+2)-sav-1,build(rt[T],1,n);
        for(int i=T-1,pos=m;i;i--){
            rt[i]=rt[i+1];
            for(;pos&&node[pos].a==sav[i];pos--){
                int u=find(rt[i],node[pos].u),v=find(rt[i],node[pos].v);
                if(val[u]!=val[v]){
                    if(dep[u]>dep[v])swap(u,v);
                    val[update(rt[i],rt[i],1,n,val[u])]=val[v];
                    int w=update(rt[i],rt[i],1,n,val[v]);
                    val[w]=val[v],minn[w]=min(minn[u],minn[v]),dep[w]=dep[v]+(dep[u]==dep[v]);
                }
            }
        }
        for(;q;q--){
            int u=(read()+K*lasans-1)%n+1,p=(read()+K*lasans)%(S+1);
            printf("%u\n",lasans=minn[find(rt[upper_bound(sav+1,sav+T+1,p)-sav],u)]);
        }
    }
    return 0;
}
[NOI2018] 归程

 

posted @ 2021-03-22 16:44  QDK_Storm  阅读(33)  评论(0编辑  收藏  举报