1. 程式人生 > >POJ2374 Fence Obstacle Course 【線段樹】

POJ2374 Fence Obstacle Course 【線段樹】

柵欄 線段樹優化 畫圖 \n RR 優化 #define 出現 開始

題目鏈接

POJ2374

題解

題意:
給出\(n\)個平行於\(x\)軸的柵欄,求從一側柵欄的某個位置出發,繞過所有柵欄到達另一側\(x = 0\)位置的最短水平距離

往上說都是線段樹優化dp
我寫了一個奇怪的線段樹過了,似乎並沒有和dp沾邊

因為每次都是從某個柵欄的端點出發,到達某個位置的值等於[所有這些可出發的端點已產生的代價 + 到達這個點的距離] 的最小值
就用線段樹維護每個區間
\(lm[u]\)表示在這個區間內的端點到達左端點的最小代價
\(rm[u]\)表示到右端點的最小代價

然後每出現一層柵欄,計算出左右端點來更新線段樹,同時清空被新柵欄覆蓋的區間【因為這些端點已經無法直接到達下一層區間了】

PS:
一開始看錯題了,柵欄的順序是反過來的
在察覺看錯題之前,拿了往上若幹AC程序對拍
拍出一個驚人小數據,竟所有程序輸出都不一樣!!
5 0
3 4
-4 5
-4 0
1 3
2 3
最終畫圖欽定,,我把它們hack掉了

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#define LL long long int
#define Redge(u) for (int k = h[u],to; k; k = ed[k].nxt)
#define REP(i,n) for (int i = 1; i <= (n); i++) #define cls(s) memset(s,0,sizeof(s)) #define ls (u << 1) #define rs (u << 1 | 1) using namespace std; const int maxn = 200005,maxm = 100005,INF = 1000000000; inline int read(){ int out = 0,flag = 1; char c = getchar(); while (c < 48 || c > 57
){if (c == ‘-‘) flag = -1; c = getchar();} while (c >= 48 && c <= 57){out = (out << 3) + (out << 1) + c - 48; c = getchar();} return out * flag; } const int ll = 1,rr = 200001,P = 100001; int lm[maxn << 2],rm[maxn << 2],tag[maxn << 2]; void upd(int u,int l,int r){ int mid = l + r >> 1; lm[u] = min(lm[ls],lm[rs] + (mid - l + 1)); rm[u] = min(rm[rs],rm[ls] + (r - mid)); } void pd(int u){ if (tag[u]){ lm[ls] = rm[ls] = lm[rs] = rm[rs] = INF; tag[ls] = tag[rs] = 1; tag[u] = 0; } } void modify(int u,int l,int r,int pos,int v){ if (l == r){ lm[u] = min(lm[u],v); rm[u] = min(rm[u],v); return; } pd(u); int mid = l + r >> 1; if (mid >= pos) modify(ls,l,mid,pos,v); else modify(rs,mid + 1,r,pos,v); upd(u,l,r); } void reset(int u,int l,int r,int L,int R){ if (l >= L && r <= R){lm[u] = rm[u] = INF; tag[u] = 1; return;} pd(u); int mid = l + r >> 1; if (mid >= L) reset(ls,l,mid,L,R); if (mid < R) reset(rs,mid + 1,r,L,R); upd(u,l,r); } int query(int u,int l,int r,int pos){ if (l == r) return min(lm[u],rm[u]); pd(u); int mid = l + r >> 1; if (mid >= pos) return min(lm[rs] + (mid - pos + 1),query(ls,l,mid,pos)); return min(rm[ls] + (pos - mid),query(rs,mid + 1,r,pos)); } void build(int u,int l,int r){ if (l == r){lm[u] = rm[u] = INF; return;} int mid = l + r >> 1; build(ls,l,mid); build(rs,mid + 1,r); upd(u,l,r); } int ql[maxn],qr[maxn]; int main(){ int n,s,l,r,ld,rd; while (~scanf("%d%d",&n,&s)){ s += P; build(1,ll,rr); modify(1,ll,rr,s,0); for (int i = 1; i <= n; i++) ql[i] = read(),qr[i] = read(); for (int i = n; i; i--){ l = ql[i] + P; r = qr[i] + P; ld = query(1,ll,rr,l); rd = query(1,ll,rr,r); if (l + 1 <= r - 1) reset(1,ll,rr,l + 1,r - 1); modify(1,ll,rr,l,ld); modify(1,ll,rr,r,rd); } printf("%d\n",query(1,ll,rr,P)); } return 0; }

POJ2374 Fence Obstacle Course 【線段樹】