hdu-4302-Holedox Eating-线段树-单点更新,有策略的单点查询

本文介绍了一种基于区间查询和单点更新的算法实现,通过维护区间内的元素状态,高效地处理鼠标的移动和吃蛋糕的操作。具体实现包括构建、更新和查询区间树等关键步骤。

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

一开始实在是不知道怎么做,后来经过指导,猛然发现,只需要记录某个区间内是否有值即可。

flag[i]:代表i区间内,共有的蛋糕数量。

放置蛋糕的时候很好操作,单点更新。

ip:老鼠当前的位置

寻找吃哪一个蛋糕的时候:

1,要寻找0-ip这个区间内,位置最大的一个蛋糕的位置,记为ll。

2,要寻找ip-n这个区间内,位置最小的一个蛋糕的位置,记为rr。

找到ll,rr之后,就可以根据ll,rr跟ip的关系来确定该吃ll还是rr了。

如何寻找ll呢?

如果在某个区间的右半边区间找到了一个数,那么,这个区间的左半边区间肯定就不用寻找了。

如果这个区间的大小为1,那么这个区间内需要的数就肯定是这个数了。

如果某个区间的flag为0,那么这个区间肯定不存在蛋糕。

如果某个区间不包含0-ip,那么这个区间也肯定找不到ll。

于是,我们写出了寻找ll的函数:

int query(int ll,int rr,int l,int r,int rt)
{
    if(rr<l||ll>r)return -INF;
    if(flag[rt]==0)return -INF;
    if(l==r)
    {
        if(flag[rt])return l;
        else return -INF;
    }
    int ans=-INF;
    ans=query(ll,rr,rson);
    if(ans==-INF)ans=query(ll,rr,lson);
    return ans;
}

寻找rr的原理与寻找ll的原理相同。

总体代码:

#include<stdio.h>
#include<string.h>
#include<iostream>
#include<algorithm>
#include<math.h>
#include<stack>
using namespace std;
#define INF 99999999
#define lmin 0
#define rmax n
#define lson l,(l+r)/2,rt<<1
#define rson (l+r)/2+1,r,rt<<1|1
#define root lmin,rmax,1
#define maxn 110000
int flag[maxn*4];
void push_up(int rt)
{
    flag[rt]=flag[rt<<1]+flag[rt<<1|1];
}
void push_down(int rt)
{

}
void creat(int l,int r,int rt)
{
    flag[rt]=0;
    if(l!=r)
    {
        creat(lson);
        creat(rson);
    }
}
void update(int st,int x,int l,int r,int rt)
{
    if(r<st||l>st)return;
    if(l==r&&l==st)
    {
        flag[rt]+=x;
        return;
    }
    update(st,x,lson);
    update(st,x,rson);
    push_up(rt);
}
int query(int ll,int rr,int l,int r,int rt)
{
    if(rr<l||ll>r)return -INF;
    if(flag[rt]==0)return -INF;
    if(l==r)
    {
        if(flag[rt])return l;
        else return -INF;
    }
    int ans=-INF;
    ans=query(ll,rr,rson);
    if(ans==-INF)ans=query(ll,rr,lson);
    return ans;
}
int query1(int ll,int rr,int l,int r,int rt)
{
   // cout<<ll<<" "<<rr<<" "<<l<<" "<<r<<" "<<flag[rt]<<endl;
    if(rr<l||ll>r)return INF;
    if(flag[rt]==0)return INF;
    if(l==r)
    {
        if(flag[rt])return l;
        else return INF;
    }
    int ans=INF;
    ans=query1(ll,rr,lson);
    if(ans==INF)ans=query1(ll,rr,rson);
    return ans;
}
int main()
{
    int cas,T;
    int n,m;
    int l,r,mid;
    int k,a,b,c;
    int m1,m2;
    scanf("%d",&T);
    cas=0;
    while(T--)
    {
        cas++;
        int sum=0;
        scanf("%d%d",&n,&m);
        creat(root);
        int ip=0;
        int f=0;
        while(m--)
        {
            scanf("%d",&k);
            if(k==1)
            {
                int l=query(0,ip,root);
                int r=query1(ip,n,root);
               // cout<<l<<" "<<r<<endl;
                if(l>=0||r<=n)
                {
                    int ll=ip-l;
                    int rr=r-ip;
                    if(ll==rr&&f==1)mid=l;
                    else if(ll==rr&&f==0)mid=r;
                    else if(ll<rr)
                    {
                        mid=l;
                        f=1;
                    }
                    else if(ll>rr)
                    {
                        mid=r;
                        f=0;
                    }
                    int cha=mid-ip;
                    if(cha<0)cha=-cha;
                    sum+=cha;
                    ip=mid;
                    update(mid,-1,root);
                }
            }
            else
            {
                scanf("%d",&a);
                update(a,1,root);
            }
        }
        printf("Case %d: %d\n",cas,sum);
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值