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

一開始实在是不知道怎么做,后来经过指导,猛然发现,仅仅须要记录某个区间内是否有值就可以。

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;
}

hdu-4302-Holedox Eating-线段树-单点更新,有策略的单点查询,布布扣,bubuko.com

时间: 2024-10-10 01:56:59

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

HDU 3577 Fast Arrangement (线段树区间更新)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3577 题意不好理解,给你数字k表示这里车最多同时坐k个人,然后有q个询问,每个询问是每个人的上车和下车时间,每个人按次序上车,问哪些人能上车输出他们的序号. 这题用线段树的成段更新,把每个人的上下车时间看做一个线段,每次上车就把这个区间都加1,但是上车的前提是这个区间上的最大值不超过k.有个坑点就是一个人上下车的时间是左闭右开区间,可以想到要是一个人下车,另一个人上车,这个情况下这个点的大小还是不变

HDU 4902 Nice boat --线段树(区间更新)

题意:给一个数字序列,第一类操作是将[l,r]内的数全赋为x ,第二类操作是将[l,r]中大于x的数赋为该数与x的gcd,若干操作后输出整个序列. 解法: 本题线段树要维护的最重要的东西就是一个区间内所有数是否相等的标记.只维护这个东西都可以做出来. 我当时想歪了,想到维护Max[rt]表示该段的最大值,最大值如果<=x的话就不用更新了,但是好像加了这个“优化”跑的更慢了. 我想大概是因为如果两个子树最大值或者整个两个子树的数不完全相等的话,根本不能直接下传这个值或者下传gcd,因为你不知道要更

hdu 1698+poj 3468 (线段树 区间更新)

http://acm.hdu.edu.cn/showproblem.php?pid=1698 这个题意翻译起来有点猥琐啊,还是和谐一点吧 和涂颜色差不多,区间初始都为1,然后操作都是将x到y改为z,注意 是改为z,不是加或减,最后输出区间总值 也是线段树加lazy操作 1 #include<cstdio> 2 using namespace std; 3 struct point { 4 int l,r; 5 int val,sum; 6 }; 7 point tree[400007]; 8

HDU 4302 Holedox Eating(multiset)

http://acm.hdu.edu.cn/showproblem.php?pid=4302 题意: 在一条直线上,会有多条命令,如果是0,那么就会在x位置处出现一个蛋糕,如果是1,某人就会找到最近的蛋糕去吃.一开始在0坐标处,如果两边都有距离相同的蛋糕,则不改变方向.求经过的总距离. 思路: multiset维护,每次1命令时在multiset找距离最近的即可. 1 #include<iostream> 2 #include<cstdio> 3 #include<set&g

hdu 3397 Sequence operation 线段树 区间更新 区间合并

题意: 5种操作,所有数字都为0或1 0 a b:将[a,b]置0 1 a b:将[a,b]置1 2 a b:[a,b]中的0和1互换 3 a b:查询[a,b]中的1的数量 4 a b:查询[a,b]中的最长连续1串的长度 这题看题目就很裸,综合了区间更新,区间合并 我一开始把更新操作全放一个变量,但是在push_down的时候很麻烦,情况很多,容易漏,后来改成下面的 更新的操作可以分为两类,一个是置值(stv),一个是互换(swp).如果stv!=-1,则更新儿子节点的stv,并将儿子的sw

HDU 2795 Billboard (线段树单点更新)

题意:h,w,n:有一个h*w尺寸的木板,n张1*wi的海报,贴海报的位置尽量高,尽量往左,问每张海报贴的高度 看到1 <= h,w <= 10^9; 1 <= n <= 200,000,应该就是线段树了. 关键在怎么建树,这里我们对h进行分割,每个高度都有等长的w,我们从上往下贴,如果当前高度 (在同一高度上l==r)的长度可以满足wi则可以贴,否则继续往下寻找. #include <iostream> #include <stdio.h> #includ

HDU 3874 Necklace (线段树单点更新+区间查询+离线操作)

Problem Description Mery has a beautiful necklace. The necklace is made up of N magic balls. Each ball has a beautiful value. The balls with the same beautiful value look the same, so if two or more balls have the same beautiful value, we just count

HDU 3074-Multiply game(线段树:单点更新,区间求积)

Multiply game Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 1450    Accepted Submission(s): 508 Problem Description Tired of playing computer games, alpc23 is planning to play a game on numbe

HDU 1698 Just a Hook (线段树,区间更新)

Just a Hook Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 17214    Accepted Submission(s): 8600 Problem Description In the game of DotA, Pudge’s meat hook is actually the most horrible thing f

hdu 1394 Minimum Inversion Number 线段树 点更新

// hdu 1394 Minimum Inversion Number 线段树 点更新 // // 典型线段树的单点更新 // // 对于求逆序数,刚开始还真的是很年轻啊,裸的按照冒泡排序 // 求出最初始的逆序数,然后按照公式递推,结果就呵呵了 // // 发现大牛都是用线段树和树状数组之类的做的,而自己又在学 // 线段树,所以就敲了线段树. // // 线段树的节点保存一段区间( L,R )内0,1...n一共出现了多少个. // 因为每个数是0,1,2...n-1且没有重复的数字. /