当前位置:编程学习 > C/C++ >>

[线段树]POJ 2374 Fence Obstacle Course

我们可以开一个一维数组w[],数组下标就是区间的端点值,cow刚开始在w[s]处。碰到一个区间后,我们看这个区间会覆盖多少个值(实际就是到前面区间的端点所花的步数),枚举这些值更新当前区间两个端点值,枚举完后,把覆盖的值删掉,添加这两个新的端点值,区间外的值不用考虑。最后在从小到大枚举这些端点值加上距离原点的距离即为答案,当然要从这些值中选择最小的。

这其中涉及到删除区间覆盖的值和添加两端点的值。如果用数组来做,最坏情况每次都是O(n),链表每次遍历也会比较浪费时间。

这里就选择线段树了。线段树删除和添加是logn,每次删除的次数依赖剩余的端点,而每个端点最多被添加一次,删除一次,所以复杂度为2*N*logL,L为区间最大距离。

PS:悲了个剧,用链表来做,500ms过了,而且代码也短

线段树,1500ms过,而且代码量多了几乎1倍

。。。。。。。。

先看链表代码:

[cpp] 
#include <cstdio> 
#include <cstring> 
#include <utility> 
#include <iostream> 
#include <list> 
using namespace std; 
#define MP make_pair 
#define x first 
#define y second 
const int INF = 0x3f3f3f3f; 
const int maxn = 100010; 
typedef pair<int, int> pii; 
list<pii> p; 
list<pii>::iterator it; 
int w[maxn][2]; 
inline int f(int v) 

    return v >= 0 ? v : -v; 

int main() 

    int n, s; 
    int l, r; 
    scanf("%d %d", &n, &s); 
    for(int i = 0; i < n; i++) scanf("%d %d", &w[i][0], &w[i][1]); 
    p.push_back(MP(0, s)); 
    for(int i = n - 1; i >= 0; i--){ 
        l = w[i][0], r = w[i][1]; 
        int ll = INF, rr = INF; 
        for(it = p.begin(); it != p.end(); ){ 
            if(l <= it->y && it->y <= r){ 
                ll = min(ll, it->x + f(it->y - l)); 
                rr = min(rr, it->x + f(it->y - r)); 
                it = p.erase(it); 
            }else if(it->y > r) 
                break; 
            else it++; 
        } 
        if(ll < INF){ 
            p.insert(it, MP(ll, l)); 
            p.insert(it, MP(rr, r)); 
        } 
    } 
    int ans = INF; 
    for(it = p.begin(); it != p.end(); it++){ 
        ans = min(ans, it->x + f(it->y)); 
    } 
    printf("%d\n", ans); 


然后线段树代码:

[cpp]
#include <cstdio> 
#include <cstring> 
#include <utility> 
#include <iostream> 
using namespace std; 
#define lson l, m, rt << 1 
#define rson m + 1, r, rt << 1 | 1 
const int INF = 0x3f3f3f3f; 
const int maxn = 200010; 
typedef pair<int, int> pii; 
int cover[maxn << 2], MinV[maxn << 2], P[maxn << 2]; 
int w[maxn][2]; 
void PushUp(int rt) 

    MinV[rt] = MinV[rt << 1]; 
    P[rt] = P[rt << 1]; 
    if(MinV[rt] > MinV[rt << 1 | 1]){ 
        MinV[rt] = MinV[rt << 1 | 1]; 
        P[rt] = P[rt << 1 | 1]; 
    } 

void update(int p, int c, int l, int r, int rt) 

    if(l == r) { 
        MinV[rt] = c; 
        P[rt] = l; 
        return ; 
    } 
    int m = (l + r) >> 1; 
    if(p <= m) update(p, c, lson); 
    else update(p, c, rson); 
    PushUp(rt); 

pii query(int L, int R, int l, int r, int rt) 

    if(L <= l && r <= R) return pii(MinV[rt], P[rt]); 
    int m = (l + r) >> 1; 
    pii u(INF, 0), v; 
    if(L <= m) { 
        v = query(L, R, lson); 
        if(u.first > v.first) u = v; 
    } 
    if(m < R) { 
        v = query(L, R, rson); 
        if(u.first > v.first) u = v; 
    } 
    PushUp(rt); 
    return u; 

 
inline int f(int x) 

    return x >= 0 ? x : -x; 

int main() 

    int n, s; 
    int L = INF, R = -INF; 
    int l, r; 
    memset(MinV, 0x3f, sizeof(MinV)); 
    scanf("%d %d", &n, &s); 
    for(int i = 0; i < n; i++){ 
        scanf("%d %d", &w[i][0], &w[i][1]); 
        L = min(L, w[i][0]); 
        R = max(R, w[i][1]);  
    } 
    update(w[n - 1][0], f(s - w[n - 1][0]), L, R, 1); 
    update(w[n - 1][1], f(s - w[n - 1][1]), L, R, 1); 
    for(int i = n - 2; i >= 0; i--){ 
        l = w[i][0], r = w[i][1]; 
        int ll = INF, rr = INF; 
        while(true){ 
            pii u = query(l, r, L, R, 1); 
            if(u.first == INF) break; 
            ll = min(ll, u.first + f(u.second - l)); 
            rr = min(rr, u.first + f(u.second - r)); 
            update(u.second, INF,

补充:软件开发 , C++ ,
CopyRight © 2022 站长资源库 编程知识问答 zzzyk.com All Rights Reserved
部分文章来自网络,