• UOJ #236. 【IOI2016】railroad


    Description

    Anna 在一个游乐园工作。她负责建造一个新的过山车铁路。她已经设计了影响过山车速度的 nn 个特殊的路段(方便起见标记为 00 到 n−1n−1)。现在 Anna 必须要把这些特殊的路段放在一起并提出一个过山车的最后设计。为了简化问题,你可以假设过山车的长度为零。

    对于 00 和 n−1n−1 之间的每个 ii,这个特殊的路段 ii 具有如下两个性质:

    当进入这个路段时,有一个速度限制:过山车的速度必须小于或等于 sisi km/h(每小时千米),
    当离开这个路段时,过山车的速度刚好是 titi km/h,不管过山车进入该路段时的速度如何。

    最后完成的过山车设计是一个以某种顺序包含这 nn 个特殊路段的单一铁路线。这 nn 个路段中的每一个应当被使用刚好一次。连续的路段之前用铁轨来连接。Anna 应该选择这 nn 个路段的顺序,然后确定每段铁轨的长度。铁轨的长度以米来衡量,可以是任意的非负整数(可以为零)。

    两个特殊路段之间的每 11 米铁轨可以将过山车的速度减慢 11 km/h。在这个过山车铁路的起点,过山车按照 Anna 选择的顺序进入第一个特殊路段时的速度是 11 km/h。

    最后的设计还必须满足以下要求:

    过山车在进入这些特殊路段时不能违反任一个速度限制;
    过山车的速度在任意时刻为正。

    在所有子任务中(子任务 33 除外),你的任务是找出这些路段之间铁轨的最小可能总长度(这些路段之间铁轨总长度的最小值)。对于子任务 33 你只需要检查是否存在一个有效的过山车设计,使得每段铁轨的长度为零。

    Solution

    我们可以把这个过程看成速度的起落,于是我们把速度离散成点
    对于每组((s_i,t_i)),(s_i->t_i)连边,这样形成很多条边
    我们可以把速度的变化看作这个图中的一条欧拉路,这样也得先满足欧拉路的条件
    经过每一段区间 ([x,x+1]) 的向左的边和向右的边的差的绝对值不超过(1)(因为这是一个反复横跳的过程)
    这样我们就得到了每一个点的度数 (in[i]) (向左-向右的边数)
    如果 (in[i]<0) 我们要做的是让速度变慢,那么就加入 (in[i])条代价为 (x_i-x_{i-1}) 的边,从而满足度数条件
    如果 (in[i]>0) 因为速度增大是不需要代价的,所以直接把度数变成 (0) 即可

    所以前面一部分相当于是把有交的边先处理好(同一个连通块)
    最后由于图要连通,所以再做一遍最小生成树,实质是构造出不同连通块的摆放顺序,使得代价最小

    #include<bits/stdc++.h>
    #include "railroad.h"
    using namespace std;
    typedef long long ll;
    const int N=400005;
    int n,b[N],num=0,m,fa[N],sum[N];
    inline int find(int x){return fa[x]==x?x:fa[x]=find(fa[x]);}
    struct sub{
    	int x,y,z;
    	bool operator <(const sub &p)const{return z<p.z;}
    }e[N];
    long long plan_roller_coaster(std::vector<int> s, std::vector<int> t) {
        n = (int) s.size();
    	 for(int i=0;i<n;i++)b[++num]=s[i],b[++num]=t[i];
    	 sort(b+1,b+num+1);m=unique(b+1,b+num+1)-b-1;
    	 for(int i=1;i<=m;i++)fa[i]=i;
    	 for(int i=0;i<n;i++){
    		 s[i]=lower_bound(b+1,b+m+1,s[i])-b;
    		 t[i]=lower_bound(b+1,b+m+1,t[i])-b;
    		 fa[find(t[i])]=find(s[i]);
    		 sum[s[i]]--,sum[t[i]]++;
    	 }
    	 int cnt=0;ll ans=0;
    	 sum[1]++;sum[m]--;
    	 if(find(1)!=find(m))fa[find(m)]=find(1);
    	 for(int i=m;i>1;i--){
    		 if(sum[i]){
    			 if(sum[i]>0)ans+=1ll*sum[i]*(b[i]-b[i-1]);
    			 sum[i-1]+=sum[i];fa[find(i)]=find(i-1);
    		 }
    		 e[++cnt]=(sub){i-1,i,b[i]-b[i-1]};
    	 }
    	 sort(e+1,e+cnt+1);
    	 for(int i=1;i<=cnt;i++){
    		 int x=e[i].x,y=e[i].y;
    		 if(find(x)==find(y))continue;
    		 fa[find(y)]=find(x);
    		 ans+=e[i].z;
    	 }
        return ans;
    }
    
    
  • 相关阅读:
    关于这个 blog
    P6499 [COCI2016-2017#2] Burza 题解
    CF1172F Nauuo and Bug 题解
    CF1479D Odd Mineral Resource 题解
    CF1442E Black, White and Grey Tree 题解
    CF1442D Sum 题解
    CF1025D Recovering BST 题解
    CF1056E Check Transcription 题解
    CF1025F Disjoint Triangles 题解
    红包算法的PHP实现
  • 原文地址:https://www.cnblogs.com/Yuzao/p/8490631.html
Copyright © 2020-2023  润新知