石油大--2020年秋季组队训练赛第十二场----J、Greedy Termite(线段树)

题面:
在这里插入图片描述
题意:
给定正整数 n n n 和起始位置 s s s
n n n 表示有 n n n 个杆子,每个杆子由属性 ( x i , h i ) (x_i,h_i) (xi,hi) 构成,表示在 x i x_i xi 处有一根高度为 h i h_i hi 的杆子。初始时在 s s s 杆子处。

每爬到一个杆子(途径不算)我就会把这个杆子扔掉。

从当前位置要去的下一个杆子符合以下条件:假设当前在杆子 i i i 处。
(1)当前还在场上的杆子。
(2)选择 h j − ∣ x i − x j ∣ h_j-|x_i-x_j| hjxixj 最大的杆子。
(3)如果有多个 h j − ∣ x i − x j ∣ h_j-|x_i-x_j| hjxixj 最大的杆子,选择 ∣ x i − x j ∣ |x_i-x_j| xixj 最小的杆子。
(4)如果有多个 h j − ∣ x i − x j ∣ h_j-|x_i-x_j| hjxixj 最大的杆子,且有多个 ∣ x i − x j ∣ |x_i-x_j| xixj 最小的杆子。选择最左侧的杆子。

题解:
考虑对于某一个确定的 x i x_i xi,如果 x i < = x j x_i<=x_j xi<=xj,那么条件(2),(3)转化为 m a x ( h j − x j ) , m i n ( x j ) max(h_j-x_j),min(x_j) max(hjxj)min(xj)。如果 x i > = x j x_i>=x_j xi>=xj,那么条件(2),(3) 转化为 m a x ( h j + x j ) , m i n ( − x j ) max(h_j+x_j),min(-x_j) max(hj+xj)min(xj)

那么我们开两棵线段树,一棵线段树维护 m a x ( h j − x j ) , m i n ( x j ) max(h_j-x_j),min(x_j) max(hjxj)min(xj),另一棵线段树维护 m a x ( h j + x j ) , m i n ( − x j ) max(h_j+x_j),min(-x_j) max(hj+xj)min(xj)

时间复杂度 O ( n l o g n ) O(nlogn) O(nlogn)

代码:

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<string>
#include<queue>
#include<bitset>
#include<map>
#include<unordered_map>
#include<set>
namespace onlyzhao
{
    #define ui unsigned int
    #define ll long long
    #define llu unsigned ll
    #define ld long double
    #define pr make_pair
    #define pb push_back
    #define lc (cnt<<1)
    #define rc (cnt<<1|1)
    #define len(x)  (t[(x)].r-t[(x)].l+1)
    #define tmid ((l+r)>>1)
    #define fhead(x) for(int i=head[(x)];i;i=nt[i])
    //#define max(x,y) ((x)>(y)?(x):(y))
    //#define min(x,y) ((x)>(y)?(y):(x))
    #define one(n) for(int i=1;i<=(n);i++)
    #define rone(n) for(int i=(n);i>=1;i--)
    #define fone(i,x,n) for(int i=(x);i<=(n);i++)
    #define frone(i,n,x) for(int i=(n);i>=(x);i--)
    #define fonk(i,x,n,k) for(int i=(x);i<=(n);i+=(k))
    #define fronk(i,n,x,k) for(int i=(n);i>=(x);i-=(k))
    #define two(n,m) for(int i=1;i<=(n);i++) for(int j=1;j<=(m);j++)
    #define ftwo(i,n,j,m) for(int i=1;i<=(n);i++) for(int j=1;j<=(m);j++)
    #define fvc(vc) for(int i=0;i<vc.size();i++)
    #define frvc(vc) for(int i=vc.size()-1;i>=0;i--)
    #define forvc(i,vc) for(int i=0;i<vc.size();i++)
    #define forrvc(i,vc) for(int i=vc.size()-1;i>=0;i--)
    #define cls(a) memset(a,0,sizeof(a))
    #define cls1(a) memset(a,-1,sizeof(a))
    #define clsmax(a) memset(a,0x3f,sizeof(a))
    #define clsmin(a) memset(a,0x80,sizeof(a))
    #define cln(a,num) memset(a,0,sizeof(a[0])*num)
    #define cln1(a,num) memset(a,-1,sizeof(a[0])*num)
    #define clnmax(a,num) memset(a,0x3f,sizeof(a[0])*num)
    #define clnmin(a,num) memset(a,0x80,sizeof(a[0])*num)
    #define sc(x) scanf("%d",&x)
    #define sc2(x,y) scanf("%d%d",&x,&y)
    #define sc3(x,y,z) scanf("%d%d%d",&x,&y,&z)
    #define scl(x) scanf("%lld",&x)
    #define scl2(x,y) scanf("%lld%lld",&x,&y)
    #define scl3(x,y,z) scanf("%lld%lld%lld",&x,&y,&z)
    #define scf(x) scanf("%lf",&x)
    #define scf2(x,y) scanf("%lf%lf",&x,&y)
    #define scf3(x,y,z) scanf("%lf%lf%lf",&x,&y,&z)
    #define scs(x) scanf("%s",x+1)
    #define scs0(x) scanf("%s",x)
    #define scline(x) scanf("%[^\n]%*c",x+1)
    #define scline0(x) scanf("%[^\n]%*c",x)
    #define pcc(x) putchar(x)
    #define pc(x) printf("%d\n",x)
    #define pc2(x,y) printf("%d %d\n",x,y)
    #define pc3(x,y,z) printf("%d %d %d\n",x,y,z)
    #define pck(x) printf("%d ",x)
    #define pcl(x) printf("%lld\n",x)
    #define pcl2(x,y) printf("%lld %lld\n",x,y)
    #define pcl3(x,y,z) printf("%lld %lld %d\n",x,y,z)
    #define pclk(x) printf("%lld ",x)
    #define pcf2(x) printf("%.2f\n",x)
    #define pcf6(x) printf("%.6f\n",x)
    #define pcf8(x) printf("%.8f\n",x)
    #define pcs(x) printf("%s\n",x+1)
    #define pcs0(x) printf("%s\n",x)
    #define pcline(x) printf("%d**********\n",x)
    #define casett int tt;sc(tt);int pp=0;while(tt--)

    char buffer[100001],*S,*T;
    inline char Get_Char()
    {
        if (S==T)
        {
            T=(S=buffer)+fread(buffer,1,100001,stdin);
            if (S==T) return EOF;
        }
        return *S++;
    }
    inline int read()
    {
        char c;int re=0;
        for(c=Get_Char();c<'0'||c>'9';c=Get_Char());
        while(c>='0'&&c<='9') re=re*10+(c-'0'),c=Get_Char();
        return re;
    }
};
using namespace onlyzhao;
using namespace std;

const int inf=0x3f3f3f3f;
const ll lnf=0x3f3f3f3f3f3f3f3f;
const double dnf=1e9;
const int mod=998244353;
const double eps=1e-8;
const double pi=acos(-1.0);
const int hp=13331;
const int maxn=100100;
const int maxm=100100;
const int up=100100;

ll h[maxn],x[maxn];
int n,s;
struct node
{
    int l,r;
    ll maxx,minn;
    int id;
};

void pushup(node &now,const node &l,const node &r)
{
    if(l.maxx>r.maxx)
    {
        now.maxx=l.maxx;
        now.minn=l.minn;
        now.id=l.id;
    }
    else if(l.maxx<r.maxx)
    {
        now.maxx=r.maxx;
        now.minn=r.minn;
        now.id=r.id;
    }
    else
    {
        if(l.minn<r.minn)
        {
            now.maxx=l.maxx;
            now.minn=l.minn;
            now.id=l.id;
        }
        else if(l.minn>r.minn)
        {
            now.maxx=r.maxx;
            now.minn=r.minn;
            now.id=r.id;
        }
        else
        {
            if(l.id<r.id)
            {
                now.maxx=l.maxx;
                now.minn=l.minn;
                now.id=l.id;
            }
            else
            {
                now.maxx=r.maxx;
                now.minn=r.minn;
                now.id=r.id;
            }
        }
    }
}

struct xds
{
    node t[maxn<<2];

    void build(int l,int r,int cnt)
    {
        t[cnt].l=l,t[cnt].r=r;
        if(l==r)
        {
            t[cnt].maxx=h[l]-x[l];
            t[cnt].minn=x[l];
            t[cnt].id=l;
            return ;
        }
        build(l,tmid,lc);
        build(tmid+1,r,rc);
        pushup(t[cnt],t[lc],t[rc]);
    }
    node ask(int l,int r,int cnt)
    {
        if(l<=t[cnt].l&&t[cnt].r<=r)
            return t[cnt];

        node now;
        if(r<t[rc].l) now=ask(l,r,lc);
        else if(l>t[lc].r) now=ask(l,r,rc);
        else pushup(now,ask(l,r,lc),ask(l,r,rc));
        return now;
    }

    void change(int pos,int cnt)
    {
        if(t[cnt].l==t[cnt].r)
        {
            t[cnt].maxx=-lnf;
            t[cnt].minn=lnf;
            t[cnt].id=-1;
            return ;
        }
        if(pos<=t[lc].r) change(pos,lc);
        else change(pos,rc);
        pushup(t[cnt],t[lc],t[rc]);
    }
}t1,t2;


set<ll>se;
map<ll,int>mp;

int main(void)
{
    scanf("%d%d",&n,&s);
    for(int i=1;i<=n;i++)
    {
        scanf("%lld%lld",&x[i],&h[i]);
        se.insert(x[i]);
        mp[x[i]]=i;
    }

    t1.build(1,n,1);
    for(int i=1;i<=n;i++)
        x[i]=-x[i];
    t2.build(1,n,1);
    for(int i=1;i<=n;i++)
        x[i]=-x[i];

    t1.change(s,1);
    t2.change(s,1);
    se.erase(x[s]);

    ll ans=0;
    ll pos=x[s];
    while(se.size())
    {
        auto now=se.upper_bound(pos);
        node cc;
        if(now==se.begin())
        {
            cc=t1.ask(1,n,1);
        }
        else if(now==se.end())
        {
            cc=t2.ask(1,n,1);
        }
        else
        {
            node xx=t2.ask(1,mp[*(--now)],1);
            node yy=t1.ask(mp[*(++now)],n,1);
            swap(xx,yy);
            xx.maxx+=pos;
            xx.minn-=pos;
            yy.maxx-=pos;
            yy.minn+=pos;
            pushup(cc,xx,yy);
        }
        ans+=abs(x[cc.id]-pos);
        t1.change(cc.id,1);
        t2.change(cc.id,1);
        se.erase(x[cc.id]);
        pos=x[cc.id];
    }
    printf("%lld\n",ans);
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值