HDU/HDOJ----4302 Holedox Eating

本文介绍了一道使用线段树解决的问题,通过构建线段树并实现查询与插入操作,寻找离目标点最近的位置。文章提供了完整的代码示例,并解释了相关算法细节。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

多校第一场比较水的一道题,用线段树查找离要求点最近的目标。当时很快就有思路了,但是一直想拿ZKW版线段树写,由于没有完全掌握其精髓,当场没有做出来,赛后用常规版写的,而且写的比较丑陋……

#include <iostream>
#include <cstdio>
#include <cmath>

#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1^1
#define ll long long
#define N 100005
#define inf 1e9
#define linf 1e9
#define rinf -1

using namespace std;

struct node{
    int left,right;
    int num,lmost,rmost;
}seg[3*N];

int min(int a,int b) { return a<b?a:b; }
int max(int a,int b) { return a>b?a:b; }

void segtree_build(int l,int r,int rt){
    //cout<<"<"<<l<<","<<r<<">"<<endl;
    seg[rt].left=l,seg[rt].right=r;
    seg[rt].num=0,seg[rt].lmost=linf,seg[rt].rmost=rinf;
    if(l==r) return ;
    int mid=(l+r)>>1;
    segtree_build(lson);
    segtree_build(rson);
}

node segtree_query(int L,int R,int l,int r,int rt){
    node ans,tl,tr;
    ans.lmost=linf,ans.rmost=rinf;
    if(L<=l&&r<=R){
        ans.lmost=min(ans.lmost,seg[rt].lmost);
        ans.rmost=max(ans.rmost,seg[rt].rmost);
        return ans;
    }
    int mid=(seg[rt].left+seg[rt].right)>>1;
    if(L<=mid){
        tl=segtree_query(L,R,lson);
        ans.lmost=min(ans.lmost,tl.lmost);
        ans.rmost=max(ans.rmost,tl.rmost);
    }
    if(R>mid){
        tr=segtree_query(L,R,rson);
        ans.lmost=min(ans.lmost,tr.lmost);
        ans.rmost=max(ans.rmost,tr.rmost);
    }
    return ans;
}

void segtree_insert(int p,int rt,int index){
    seg[rt].num+=index;
    if(seg[rt].num==0) seg[rt].lmost=linf,seg[rt].rmost=rinf;
    if(seg[rt].left==p&&seg[rt].right==p){
        if(seg[rt].num) seg[rt].lmost=p,seg[rt].rmost=p;
        return ;
    }
    int mid=(seg[rt].left+seg[rt].right)>>1;
    if(p<=mid) segtree_insert(p,rt<<1,index);
    else segtree_insert(p,rt<<1^1,index);
    if(seg[rt].num){
        seg[rt].lmost=min(seg[rt<<1].lmost,seg[rt<<1^1].lmost);
        seg[rt].rmost=max(seg[rt<<1].rmost,seg[rt<<1^1].rmost);
    }
}

void segtree_print(int L){
    for(int i=1;i<=L*2;i*=2){
        for(int j=0;j<i;j++){
            int pos=i+j;
            printf("<%d,%d> ",seg[pos].left,seg[pos].right);
            if(seg[pos].lmost==linf) printf("no ");
            else printf("%d ",seg[pos].lmost);
            if(seg[pos].rmost==rinf) printf("no ");
            else printf("%d ",seg[pos].rmost);
            printf("%d| ",seg[pos].num);
        }
        printf("\n");
        for(int k=0;k<80;k++)
            printf("-");
        printf("\n");
    }
}

int main(){
    //freopen("in.in","r",stdin);
    int T,L,n,Case=1;
    int lp,rp,ld,rd;
    scanf("%d",&T);
    while(T--){
        scanf("%d%d",&L,&n);
        segtree_build(0,L,1);
        //segtree_print(L);
        //cout<<"segtree_build done!"<<endl;
        int lst=0,pos=0,ope,p;
        ll ans=0;
        while(n--){
            scanf("%d",&ope);
            if(ope){
                lp=segtree_query(0,pos,0,L,1).rmost; ld=(lp==rinf?inf:abs(lp-pos)); //if(lp==inf) cout<<"no"<<' '; else cout<<"lp="<<lp<<' ';
                rp=segtree_query(pos,L,0,L,1).lmost; rd=(rp==linf?inf:abs(rp-pos)); //if(rp==inf) cout<<"no"<<endl; else cout<<"rp="<<rp<<endl;
                if(ld==inf&&rd==inf) continue;
                else if(ld<rd||(ld==rd&&lst==-1)){
                    pos=lp,lst=-1,ans+=(ll)ld;
                    segtree_insert(pos,1,-1);
                    //segtree_print(L);
                    //cout<<"delete "<<pos<<" done!"<<endl;
                }
                else if(ld>rd||(ld==rd&&lst==1)){
                    pos=rp,lst=1,ans+=(ll)rd;
                    segtree_insert(pos,1,-1);
                    //segtree_print(L);
                    //cout<<"delete "<<pos<<" done!"<<endl;
                }
                else if(ld==rd&&lst==0){
                    segtree_insert(pos,1,-1);
                    //segtree_print(L);
                    //cout<<"delete "<<pos<<" done!"<<endl;
                }
                //cout<<"pos="<<pos<<' '<<"lst="<<lst<<' '<<"ans="<<ans<<endl;
            }
            else{
                scanf("%d",&p);
                segtree_insert(p,1,1);
                //segtree_print(L);
                //cout<<"insert "<<p<<" done!"<<endl;
            }
        }
        printf("Case %d: %lld\n",Case++,ans);
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值