Gym - 102174G 神圣的 F2 连接着我们 (线段树优化建图 + 多源最短路)

12 篇文章 0 订阅
11 篇文章 0 订阅

Description

小白非常喜欢玩 “县际争霸” 这款游戏,虽然他的技术并不容乐观。“县际争霸” 的地图共有两个县,每个县里各有 n n n 个据点。同一个县之间的据点是互不连通的,两个县之间的据点也是互不连通的。小白的 p p p 个战斗单位在第一个县的第 x 1 , x 2 , ⋯ , x p x_1,x_2,⋯,x_p x1,x2,,xp 个据点中,而对手的 q q q 个建筑单位在第二个县第 y 1 , y 2 , ⋯ , y q y_1,y_2,⋯,y_q y1,y2,,yq 个据点中。

为了发起进攻,小白建造了很多的 “折跃棱镜”。折跃棱镜可以帮助小白的单位在两个县之间移动,而且可以有多个单位同时通过折跃棱镜。具体地说,一个折跃棱镜包含有 5 个参数信息 a , b , c , d , w , a,b,c,d,w, a,b,c,d,w代表位于第一个县任意第 x x x ( a ≤ x ≤ b ) (a\leq x \leq b) (axb) 个据点的战斗单位可以花费 w 单位时间到达第二个县的任意第 $$y ( c ≤ y ≤ d ) (c \leq y \leq d) (cyd)个据点。折跃棱镜的通道是双向的,所以位于第二个县任意第 y y y ( c ≤ y ≤ d ) (c≤y≤d) (cyd) 个据点的战斗单位也可以花费 w w w 单位时间到达第一个县的任意第 x ( a ≤ x ≤ b ) x (a≤x≤b) x(axb) 个据点。

如果一个小白的战斗单位到达了一个有敌方建筑单位的据点,那么这个战斗单位就会即刻投入战斗。当小白所有的战斗单位都投入了战斗之后,对手会感觉到压力太大而主动投降。小白想尽快结束这场战斗,请聪明的你帮他算一算,如果采用最优的调度策略,对手最早将在什么时刻投降(假设当前局面是零时刻)。如果存在战斗单位始终无法投入战斗,则请输出boring game。

Input
输入共 m + 3 m+3 m+3 行,第一行输入四个正整数 n , m , p , q ( 1 ≤ n , m , p , q ≤ 1 0 5 ) n,m,p,q (1≤n,m,p,q≤10^5) n,m,p,q(1n,m,p,q105)由空格间隔开,分别表示每个县的据点数量、折跃棱镜数量、小白的战斗单位数量和对手的建筑单位数量。

接下来的 m m m 行中,第 i i i 行输入五个正整数 a i , b i , c i , d i , w i ( 1 ≤ a i ≤ b i ≤ n , 1 ≤ c i ≤ d i ≤ n , 1 ≤ w i ≤ 1 0 9 ) ai,bi,ci,di,wi (1≤a_i≤b_i≤n,1≤c_i≤d_i≤n,1≤w_i≤10^9) ai,bi,ci,di,wi(1aibin,1cidin,1wi109) 由空格间隔开,表示第 i 个折跃棱镜的参数,具体含义见题目描述。

接下来一行输入 p 个正整数 x 1 , x 2 , ⋯ , x p ( 1 ≤ x i ≤ n ) x_1,x_2,⋯,x_p (1≤x_i≤n) x1,x2,,xp(1xin) 由空格间隔开,分别表示小白的战斗单位所在的据点位置。

最后一行输入 q 个正整数 y 1 , y 2 , ⋯ , y q ( 1 ≤ y i ≤ n ) y_1,y_2,⋯,y_q (1≤y_i≤n) y1,y2,,yq(1yin) 由空格间隔开,分别表示对手的建筑单位所在的据点。

Output
如果对手最终会主动投降,则请输出一个非负整数,表示在小白的最优调度策略下对手最早的投降时间;如果存在战斗单位始终无法投入战斗,则请输出boring game。

Example
input
5 3 2 2
2 4 1 3 1
1 1 4 5 3
1 2 3 4 2
2 3
4 5
output
4

Note
样例中,一种最优调度策略是:第一个战斗单位从第一县的 2 号据点折跃到第二县的 4 号据点即可投入战斗,这将花费 2 单位时间,同时第二个战斗单位从第一县的 3 号据点折跃到第二县的 3 号据点再折跃到第一县的 2 号据点最后折跃到第二县的 4 号据点也可投入战斗,这将花费 4 单位时间。

Solution
暴力建边不行,看到区间我们自然可以想到用线段树来优化建图。
线段树优化建图模板题:Codeforces 786B
两边各建两颗入树(自顶向下)和出树(自下而上),再把终点一起压入队列,跑多源最短路后,取所有起点的dis最大值即可

Hint
有一说一,数组范围有点难控制…

Code

#include <bits/stdc++.h>
#define ls rt << 1
#define rs rt << 1 | 1
using namespace std;
typedef long long ll;
const ll LINF = 2e18;
const int maxn = 4e6 + 7;
int n,m,p,q,cnt;

int ecnt,head[maxn];

struct Edge{
    int v,w,next;
}e[maxn<<1];

void add(int u,int v,int w){
    e[++ecnt].v = v,e[ecnt].w = w,e[ecnt].next = head[u], head[u] = ecnt;
}


int in1[maxn],out1[maxn];
int in2[maxn],out2[maxn];

int to[100007];

void build1(int rt,int l,int r){
    if(l == r){
        in1[rt] = out1[rt] = l;return ;
    }
    int mid = (l + r) >> 1; in1[rt] = ++cnt; out1[rt] = ++cnt;
    build1(ls,l,mid); build1(rs,mid+1,r);
    add(in1[rt],in1[ls],0); add(in1[rt],in1[rs],0);
    add(out1[ls],out1[rt],0); add(out1[rs],out1[rt],0);
}


void inUpdate1(int rt,int L,int R,int l,int r,int u,int w){
    if(L <= l && r <= R){
        add(u,in1[rt],w); return ;
    }
    int mid = (l + r) >> 1;
    if(L <= mid) inUpdate1(ls,L,R,l,mid,u,w);
    if(R  > mid) inUpdate1(rs,L,R,mid+1,r,u,w);
}

void outUpdate1(int rt,int L,int R,int l,int r,int u,int w){
    if(L <= l && r <= R){
        add(out1[rt],u,w); return ;
    }
    int mid = (l + r) >> 1;
    if(L <= mid) outUpdate1(ls,L,R,l,mid,u,w);
    if(R  > mid) outUpdate1(rs,L,R,mid+1,r,u,w);
}


void build2(int rt,int l,int r){
    if(l == r){
        in2[rt] = out2[rt] = ++cnt;
        to[l] = cnt;
        return ;
    }
    int mid = (l + r) >> 1; in2[rt] = ++cnt; out2[rt] = ++cnt;
    build2(ls,l,mid); build2(rs,mid+1,r);
    add(in2[rt],in2[ls],0); add(in2[rt],in2[rs],0);
    add(out2[ls],out2[rt],0); add(out2[rs],out2[rt],0);
}


void inUpdate2(int rt,int L,int R,int l,int r,int u,int w){
    if(L <= l && r <= R){
        add(u,in2[rt],w); return ;
    }
    int mid = (l + r) >> 1;
    if(L <= mid) inUpdate2(ls,L,R,l,mid,u,w);
    if(R  > mid) inUpdate2(rs,L,R,mid+1,r,u,w);
}

void outUpdate2(int rt,int L,int R,int l,int r,int u,int w){
    if(L <= l && r <= R){
        add(out2[rt],u,w); return ;
    }
    int mid = (l + r) >> 1;
    if(L <= mid) outUpdate2(ls,L,R,l,mid,u,w);
    if(R  > mid) outUpdate2(rs,L,R,mid+1,r,u,w);
}

ll dis[maxn];bool vis[maxn];
struct node{
    int now;
    ll w;
    inline bool operator<(const node&it) const{
        return w > it.w;
    }
};

int s[maxn],t[maxn];

inline ll Max(ll x1,ll x2){
    if(x1 > x2) return x1;
    return x2;
}

ll dijkstra(){
    priority_queue<node>que;
    for(int i = 1;i <= cnt;++i){
        dis[i] = LINF,vis[i] = false;
    }
    for(int i = 1;i <= q;++i){
        dis[to[t[i]]] = 0;que.push((node){to[t[i]], 1ll * 0});
    }
    while(!que.empty()){
        node x = que.top();que.pop();
        int u = x.now;if(vis[u]) continue;vis[u] = true;
        for(int i = head[u];i;i = e[i].next){
            int v = e[i].v, w = e[i].w;
            if(dis[v] > dis[u] + w){
                dis[v] = dis[u] + w;que.push((node){v,dis[v]});
            }
        }
    }

    ll res = 0;
    for(int i = 1;i <= p;++i){
        res = Max(res,dis[s[i]]);
    }
    return res;
}
int main(){
    scanf("%d%d%d%d",&n,&m,&p,&q);
    cnt = n;build1(1,1,n);build2(1,1,n);
    for(int i = 1;i <= m;++i){
        int a,b,c,d,w;scanf("%d%d%d%d%d",&a,&b,&c,&d,&w);
        int u1 = ++cnt, v1 = ++cnt, u2 = ++cnt, v2 = ++cnt;
        outUpdate1(1,a,b,1,n,u1,0);add(u1,v1,w);inUpdate2(1,c,d,1,n,v1,0);
        outUpdate2(1,c,d,1,n,v2,0);add(v2,u2,w);inUpdate1(1,a,b,1,n,u2,0);
    }
    for(int i = 1;i <= p;++i) scanf("%d",&s[i]);
    for(int i = 1;i <= q;++i) scanf("%d",&t[i]);
    ll res = dijkstra();
    if(res == LINF) printf("boring game\n"); else printf("%lld\n", res);
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值