线段树套线段树

hdu6800

#include 
#include <string.h>
#include 
#include 
#include 
#include 
#include 
#include 
#include 
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;
}

 

你可能感兴趣的:(线段树套线段树)