【upc】2020年秋季组队训练赛第十二场J Greedy Termite | 删点线段树

 状态

题目描述

There are n wooden rods vertically placed over a horizontal line. The rods are numbered 1 through n from left to right. Each rod i (1 ⩽ i ⩽ n) is placed at position xi and has a height hi .

A termite wants to eat all the rods one by one. It starts eating from an arbitrary rod s (1 ⩽ s ⩽ n). Then, after eating a rod i, the termite selects the next rod to eat based on the following method. Among the remaining rods j, the one with maximum hj - |xi-xj| is selected. If there are ties, the one with minimum |xi-xj| is selected. 
If there are still ties, the left-most rod is selected.
Your task is to calculate the total (horizontal) distance traveled by the termite to eat all the rods.

输入

The first line of the input contains two space-separated integers n, the number of rods, and s, the starting rod number (1 ⩽ s ⩽ n ⩽ 100 000). The rods are described in the next n lines. On the line 1 + i (1 ⩽ i ⩽ n), the i-th rod is specified with two space-separated integers xi (|xi| ⩽ 109 ) and hi (1 ⩽ hi ⩽ 109 ). Additionally, for each i (1 ⩽ i ⩽ n-1), xi < xi+1 .

输出

You should print a single integer denoting the total distance traveled by the termite.

样例输入 Copy

5 3
1 3
4 8
8 2
10 4
11 1

样例输出 Copy

17

题目大意:

给出一个起始位置,从起始位置开始,每次会选择一个位置,该位置满足题目中给的条件,问按照要求跳完所有点后,横坐标移动的距离是多少。

题目思路:

首先遇到绝对值就先去掉绝对值

对于一个位置i来说,对于任意的j有:

j>i : q[j].h - q[j].x + q[i].x

j<i: q[j].h + q[j].x - q[i].x

所以只需要维护一下两边的最大值即可确定到选哪个点

题目又要求,相同时选择离i最近的,也就是说左边选靠右的,右边选靠左的

此时可以直接用线段树push函数

对于每个点跳完之后的标记,可以将这个点权值设为-无穷

所以就会有 单点修改 + 区间查询

Code:

/*** keep hungry and calm CoolGuang!***/
#pragma GCC optimize(3)
#include <bits/stdc++.h>
#define debug(x) cout<<#x<<":"<<x<<endl;
#include<stdio.h>
#include<algorithm>
#include<queue>
#include<string>
#include<iostream>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> pp;
const ll INF=1e17;
const int Maxn=2e7+10;
const int maxn =5e5+10;
const int mod=1e9+9;
const int Mod = 1e9+7;
///const double eps=1e-10;
inline bool read(ll &num)
{char in;bool IsN=false;
    in=getchar();if(in==EOF) return false;while(in!='-'&&(in<'0'||in>'9')) in=getchar();if(in=='-'){ IsN=true;num=0;}else num=in-'0';while(in=getchar(),in>='0'&&in<='9'){num*=10,num+=in-'0';}if(IsN) num=-num;return true;}
ll n,m,p;
ll ma[maxn],mb[maxn];///a - > 左 ,b -> 右
int posa[maxn],posb[maxn];
void push(int k){
    if(ma[k<<1] <= ma[k<<1|1]){
        ma[k] = ma[k<<1|1];
        posa[k] = posa[k<<1|1];
    }
    else{
        ma[k] = ma[k<<1];
        posa[k] = posa[k<<1];
    }
 
    if(mb[k<<1] >= mb[k<<1|1]){
        mb[k] = mb[k<<1];
        posb[k] = posb[k<<1];
    }
    else{
        mb[k] = mb[k<<1|1];
        posb[k] = posb[k<<1|1];
    }
}
void build(int k,int l,int r){
    ma[k] = mb[k] = -INF;
    posa[k] = posb[k] = -1;
    if(l == r) return ;
    int mid = (l+r)/2;
    build(k<<1,l,mid);
    build(k<<1|1,mid+1,r);
    push(k);
}
void Modify(int k,int l,int r,int pos,ll w1,ll w2){
    if(l == r){
        ma[k] = w1;
        mb[k] = w2;
        if(w1 == -INF) posa[k] = posb[k] = -1;
        else posa[k] = posb[k] = l;
        return;
    }
    int mid = (l+r)/2;
    if(pos <= mid) Modify(k<<1,l,mid,pos,w1,w2);
    else Modify(k<<1|1,mid+1,r,pos,w1,w2);
    push(k);
}
void Query_a(int k,int x,int y,int l,int r,ll &ans,int &pos){
    if(x<=l&&y>=r){
        if(ma[k] == -INF) return;
        if(ans<ma[k]){
            ans = ma[k];
            pos = posa[k];
        }else if(ans == ma[k]) pos = max(pos,posa[k]);
        return;
    }
    int mid = (l+r)/2;
    if(x<=mid) Query_a(k<<1,x,y,l,mid,ans,pos);
    if(y>mid) Query_a(k<<1|1,x,y,mid+1,r,ans,pos);
    push(k);
}
void Query_b(int k,int x,int y,int l,int r,ll &ans,int &pos){
    if(x<=l&&y>=r){
        if(mb[k] == -INF) return;
        if(ans<mb[k]){
            ans = mb[k];
            pos = posb[k];
        }else if(ans == mb[k])
            if(~posb[k])
                pos = min(pos,posb[k]);
        return;
    }
    int mid = (l+r)/2;
    if(x<=mid) Query_b(k<<1,x,y,l,mid,ans,pos);
    if(y>mid) Query_b(k<<1|1,x,y,mid+1,r,ans,pos);
    push(k);
}
struct node{
    ll x,y;
}q[maxn];
int main()
{
    read(n);read(m);
    build(1,1,n);
    for(int i=1;i<=n;i++){
        read(q[i].x);
        read(q[i].y);
        Modify(1,1,n,i,q[i].x+q[i].y,q[i].y-q[i].x);
    }
    ll ans = 0, s = 1;
    while(1){
        ll tempm = m;
        Modify(1,1,n,m,-INF,-INF);
        ll ansa = -INF,ansb = -INF;
        int apos = -1,bpos = -1;
        if(m>1)
            Query_a(1,1,m-1,1,n,ansa,apos);
        if(m<n)
            Query_b(1,m+1,n,1,n,ansb,bpos);
        if(apos == -1 && bpos == -1) break;
        else if(apos == -1 && ~bpos) m = bpos;
        else if(~apos && bpos == -1) m = apos;
        else{
            if(ansa-q[m].x>ansb+q[m].x) m = apos;
            else if(ansa-q[m].x<ansb+q[m].x) m = bpos;
            else{
                if(q[m].x-q[apos].x <= q[bpos].x - q[m].x) m = apos;
                else m = bpos;
            }
        }
        ans += abs(q[m].x-q[tempm].x);
    }
    printf("%lld\n",ans);
    return 0;
}
/**
4 3
1 3
2 10
3 11
4 10
**/
 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

一只酷酷光儿( CoolGuang)

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值