1. 程式人生 > 實用技巧 >線段樹套線段樹

線段樹套線段樹

hdu6800

#include <iostream>
#include <string.h>
#include <queue>
#include <stack>
#include <map>
#include <stdio.h>
#include <algorithm>
#include <math.h>
#include <unordered_map>
using namespace std;
typedef long long LL;
typedef pair<int, int
> P; const int maxn = 1e5 + 10; const int maxm=maxn*18+10,maxl=maxm*8+10; struct node{ LL a[4]; node & operator = (const node &n2) { a[0]=n2.a[0]; a[1]=n2.a[1]; a[2]=n2.a[2]; a[3]=n2.a[3]; return *this; } }; int pool[maxm],*pool_tail; node info[maxl],
*info_tail; inline void reset() { pool_tail=pool; info_tail=info; } inline int * ask32(int len) { int *ret=pool_tail; pool_tail+=len; return ret; } inline node * ask256(int len) { node *ret=info_tail; info_tail+=len; return ret; } int n,qtot; LL dp[maxn]; P seq[maxn],que[maxn]; inline
void upd_min(LL &x,LL y) { if(x>y) x=y; } inline bool cmp_y(int const &u,int const &v) { return que[u].second<que[v].second; } struct Segment{ int ytot,*yque; node *info; }seg[maxn<<1|1]; inline int seg_idx(int L,int R) { return (L+R)|(L<R); } void seg_init_inner(Segment &rt,int L, int R) { if(L==R) { return; } int M=(L+R)>>1; seg_init_inner(rt, L, M); seg_init_inner(rt, M+1, R); node *cur=rt.info+seg_idx(L, R); node *lft=rt.info+seg_idx(L, M); node *rht=rt.info+seg_idx(M+1, R); cur->a[0]=min(lft->a[0],rht->a[0]); cur->a[1]=min(lft->a[1],rht->a[1]); cur->a[2]=min(lft->a[2],rht->a[2]); cur->a[3]=min(lft->a[3],rht->a[3]); } void seg_init_outer(int L,int R) { static int ord[maxn]; if(L<R) { int M=(L+R)>>1; seg_init_outer(L, M); seg_init_outer(M+1, R); inplace_merge(ord+L, ord+M+1, ord+R+1, cmp_y); } else { ord[L]=L; } Segment &rt=seg[seg_idx(L, R)]; rt.ytot=1; for(int i=L+1;i<=R;i++) { rt.ytot+=cmp_y(ord[i-1], ord[i]); } rt.yque=ask32(rt.ytot); rt.info=ask256( 2*rt.ytot-1); for(int i=L,j=0;i<=R;j++) { int u=ord[i++],y=que[u].second,xL=que[u].first,xR=xL; for(int v;i<=R&&!cmp_y(u, v=ord[i]);i++) { int tmp=que[v].first; if(tmp<xL) { xL=tmp; }else if(tmp>xR) { xR=tmp; } } rt.yque[j]=y; node *val=rt.info+(seg_idx(j, j)); val->a[0]=xL+y; val->a[1]=-xR+y; val->a[2]=-xR-y; val->a[3]=xL-y; } seg_init_inner(rt, 0, rt.ytot-1); } inline void seg_update_inner(Segment &rt,int y,node val) { for(int L=0,R=rt.ytot-1;L<=R;) { node * cur=rt.info+seg_idx(L, R); upd_min(cur->a[0], val.a[0]); upd_min(cur->a[1], val.a[1]); upd_min(cur->a[2], val.a[2]); upd_min(cur->a[3], val.a[3]); if(L==R) break; int M=(L+R)>>1; if(y<=rt.yque[M]) R=M; else L=M+1; } } inline void seg_update_outer(int pos) { int x=que[pos].first,y=que[pos].second; LL v=dp[pos]; node val; val.a[0]=v+x+y; val.a[1]=v-x+y; val.a[2]=v-x-y; val.a[3]=v+x-y; for(int L=0,R=qtot-1;L<=R;) { seg_update_inner(seg[seg_idx(L, R)], y, val); if(L==R) break; int M=(L+R)>>1; if(pos<=M) R=M; else L=M+1; } } inline LL seg_query_left_inner(Segment &rt, int x, int y) { LL ret = LLONG_MAX; for(int L = 0, R = rt.ytot - 1; L <= R; ) { node *cur = rt.info + seg_idx(L, R); if(y <= rt.yque[L]) { upd_min(ret, cur->a[1] - y); break; } else if(y >= rt.yque[R]) { upd_min(ret, cur->a[2] + y); break; } int M = (L + R) >> 1; if(y <= rt.yque[M]) { node *rht = rt.info + seg_idx(M + 1, R); upd_min(ret, rht->a[1] - y); R = M; } else { node *lft = rt.info + seg_idx(L, M); upd_min(ret, lft->a[2] + y); L = M + 1; } } if(ret != LLONG_MAX) ret += x; return ret; } inline LL seg_query_right_inner(Segment &rt, int x, int y) { LL ret = LLONG_MAX; for(int L = 0, R = rt.ytot - 1; L <= R; ) { node *cur = rt.info + seg_idx(L, R); if(y <= rt.yque[L]) { upd_min(ret, cur->a[0] - y); break; } else if(y >= rt.yque[R]) { upd_min(ret, cur->a[3] + y); break; }//已經可以確定在哪個象限有答案了 int M = (L + R) >> 1; if(y <= rt.yque[M]) { node *rht = rt.info + seg_idx(M + 1, R); //在右上方的點的貢獻也可以算了 upd_min(ret, rht->a[0] - y); R = M;//從新區間L-M再來 } else { node *lft = rt.info + seg_idx(L, M); upd_min(ret, lft->a[3] + y); L = M + 1; } } if(ret != LLONG_MAX) ret -= x; return ret; } inline LL seg_query_outer(int pos) { int x = que[pos].first, y = que[pos].second; LL ret = dp[pos]; for(int L = 0, R = qtot - 1; L < R; ) { int M = (L + R) >> 1; if(pos <= M) { upd_min(ret, seg_query_right_inner(seg[seg_idx(M + 1, R)], x, y)); R = M; } else { upd_min(ret, seg_query_left_inner(seg[seg_idx(L, M)], x, y)); L = M + 1; } } return ret; } void solve() { scanf("%d", &n); for(int i = 0; i < n; ++i) { scanf("%d%d", &seq[i].first, &seq[i].second); que[i] = seq[i]; dp[i] = 0; } sort(que, que + n); qtot = unique(que, que + n) - que; reset(); seg_init_outer(0, qtot - 1);//線段樹初始化 LL ans = 0, sum = 0; int las = lower_bound(que, que + qtot, seq[0]) - que; for(int i = 1; i < n; ++i) { LL adt = abs(seq[i].first - seq[i - 1].first) + abs(seq[i].second - seq[i - 1].second); int pos = lower_bound(que, que + qtot, seq[i]) - que; LL best = seg_query_outer(pos) - adt;//以換手的代價跑到pos,省了多少的代價 if(dp[las] > best) {//比已經省下的多 ans=min(ans , dp[las] = best ); seg_update_outer(las); } sum += adt; las = pos; } printf("%lld\n", ans + sum); } int main() { int T; scanf("%d", &T); for(int Case = 1; Case <= T; ++Case) { // printf("Case #%d:\n", Case); solve(); } return 0; }