zoukankan      html  css  js  c++  java
  • Speike [线段树, 动态规划]

    speikespeike

    ___

    color{red}{正解部分}

    将所有矩形转化为一条线段, 对答案没有影响 .

    又因为从线段的两端 “蹭” 着出去不会使答案更差,

    设从 ii 线段的上端向左 “撞” 到的第一个线段为 jj, F[i,0/1]F[i, 0/1] 表示到达 ii 线段的 上/下 端的 yy轴 最短距离,
    i,ji,j 线段的上下端 yy 坐标分别为 yi1,yi2,yj1,yj2y_{i_1},y_{i_2},y_{j_1},y_{j_2}, 则状态转移
    F[i,0]=min(F[j,0]+yj1yi1,F[j,1]+yi1yj2)F[i,1]=min(F[j,0]+yj1yi2,F[j,1]+yj2yi2)F[i, 0] = min(F[j,0] + |y_{j_1}-y_{i_1}|,F[j,1] + |y_{i_1}-y_{j_2}|)\ F[i,1] = min(F[j,0]+|y_{j_1}-y_{i_2}|, F[j,1] + |y_{j_2}-y_{i_2}|)

    向左 “撞” 到的第一条线段可以使用线段树求出 .

    时间复杂度 O(NlogN)O(NlogN) .


    color{red}{实现部分}

    • 注意离散化后的数组要不断提醒自己小心用 .
    • 左边的起点线可能会在排序中乱掉, 需要纠正到第一个位置上来 .
    #include<bits/stdc++.h>
    #define reg register
    typedef long long ll;
    
    int read(){
            char c;
            int s = 0, flag = 1;
            while((c=getchar()) && !isdigit(c))
                    if(c == '-'){ flag = -1, c = getchar(); break ; }
            while(isdigit(c)) s = s*10 + c-'0', c = getchar();
            return s * flag;
    }
    
    const int maxn = 1e6 + 10;
    
    int N;
    int Xt;
    int Lim;
    int FLAG;
    int B[maxn];
    int last[maxn][2];
    
    ll F[maxn][2];
    
    struct Line{ int bot, top, x; } lin[maxn]; 
    
    bool cmp_Line_1(Line a, Line b){ return a.x==b.x?(a.bot==b.bot?a.top<b.top:a.bot<b.bot):a.x<b.x; }
    
    ll abd(ll x){ return (x>0)?x:-x; }
    
    struct Segment_Tree{
    
            struct Node{ int l, r, val, tag; } T[maxn<<2];
            
            void Build(int k, int l, int r){
                    T[k].l = l, T[k].r = r;
                    if(l == r) return ;
                    int mid = l+r >> 1;
                    Build(k<<1, l, mid), Build(k<<1|1, mid+1, r);
            }
    
            void Push_down(int k){
                    T[k<<1].tag = T[k<<1|1].tag = T[k].tag;
                    T[k<<1].val = T[k<<1|1].val = T[k].tag;
                    T[k].tag = 0;
            }
    
            void Modify(int k, const int &ql, const int &qr, const int &aim_v){
                    int l = T[k].l, r = T[k].r;
                    if(ql <= l && r <= qr){ T[k].val = T[k].tag = aim_v; return ; }
                    if(T[k].tag) Push_down(k);
                    int mid = l+r >> 1;
                    if(ql <= mid) Modify(k<<1, ql, qr, aim_v);
                    if(qr > mid) Modify(k<<1|1, ql, qr, aim_v);
            }
    
            int Query(int k, const int &aim_x){
                    int l = T[k].l, r = T[k].r;
                    if(l == r) return T[k].val;
                    if(T[k].tag) Push_down(k);
                    int mid = l+r >> 1;
                    if(aim_x <= mid) return Query(k<<1, aim_x);
                    return Query(k<<1|1, aim_x);
            }
    
    } seg_t;
    
    void Discrtiz(){ 
            std::sort(B+1, B+Lim+1);
            Lim = std::unique(B+1, B+Lim+1) - B-1;
            for(reg int i = 1; i <= N; i ++){
                    lin[i].top = std::lower_bound(B+1, B+Lim+1, lin[i].top)-B;
                    lin[i].bot = std::lower_bound(B+1, B+Lim+1, lin[i].bot)-B;
            } 
    
            for(reg int i = 2; i <= N; i ++){
                    if(lin[i].x) break ;
                    if(!B[lin[i].top] && !B[lin[i].bot]){ std::swap(lin[i], lin[1]); break ; }
            }
    }
    
    void Init_last(){
            seg_t.Build(1, 1, Lim);
            for(reg int i = 1; i <= N; i ++){
                    last[i][0] = seg_t.Query(1, lin[i].bot);
                    last[i][1] = seg_t.Query(1, lin[i].top);
                    seg_t.Modify(1, lin[i].bot, lin[i].top, i);
            }
    }
    
    void Dp(){ 
            memset(F, 0x3f, sizeof F);
            F[1][0] = F[1][1] = 0;
            for(reg int i = 2; i <= N; i ++){
                    int ft = std::max(1, last[i][0]);
                    F[i][0] = std::min(F[ft][0] + abd(B[lin[i].bot]-B[lin[ft].bot]), F[ft][1] + abd(B[lin[i].bot]-B[lin[ft].top]));
                    ft = std::max(1, last[i][1]);
                    F[i][1] = std::min(F[ft][0] + abd(B[lin[i].top]-B[lin[ft].bot]), F[ft][1] + abd(B[lin[i].top]-B[lin[ft].top]));
            }
    }
    
    int main(){
            N = read(), Xt = read();
            FLAG = 1;
            if(Xt < 0) Xt = -Xt, FLAG = -1;
            for(reg int i = 1; i <= N; i ++){
                    int a = FLAG*read(), b = read(), c = FLAG*read(), d = read();
                    if(a > c) std::swap(a, c); if(b > d) std::swap(b, d);
                    B[++ Lim] = b, B[++ Lim] = d;
                    lin[i] = (Line){ b, d, a };
            }
    
            B[++ Lim] = 0;
            lin[++ N] = (Line){ 0, 0, 0 }, lin[++ N] = (Line){ 0, 0, Xt }; 
            std::sort(lin+1, lin+N+1, cmp_Line_1); 
            
            Discrtiz(), Init_last(), Dp();
    
            std::cout << F[N][0] + Xt;
            return 0;
    }
    
  • 相关阅读:
    数据库访问性能优化(转)
    Mysql分表和分区的区别、分库分表介绍与区别
    怎样玩转千万级别的数据(表分区)
    关于Blocking IO,non-Blokcing IO,async IO的区别和理解
    spring security四种实现方式
    使用百度网盘+Git,把版本控制托管到云端,附精彩评论
    Linux下C/C++帮助手册安装方法
    GNU自动化工具使用全过程详解,以及在线手册
    autotools工具使用 good
    使用 GNU Libtool 创建库
  • 原文地址:https://www.cnblogs.com/zbr162/p/11822487.html
Copyright © 2011-2022 走看看