Taotao Picks Apples

http://acm.hdu.edu.cn/showproblem.php?pid=6406

题意:树上有n个苹果,摘第一个苹果,之后摘的苹果必须必之前摘的苹果的高度都要高,有m次操作该变一个苹果的高度求改变后摘的数量,先求改变位置前所摘苹果的数量,再比较改变位置的苹果高度和之前所摘苹果的最高高度,如果大于采摘数量加一,否则不变此位置苹果高度变为最高高度,最后求出改变位置后面的苹果中可以采摘的苹果的编号,再用二分求出比修改位置高的最小值,加上这个位置和这个位置后面可摘的苹果数量

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<vector>
#include<map>
using namespace std;
struct node
{
    int pos;
    int pre;
    int id;
} po[100003];
bool cmp(node a,node b)
{
    if(a.pos==b.pos)
            return a.pre<b.pre;
        return a.pos<b.pos;
}
int main()
{
    int t;
    int a[100003],ans[100003],dp[100003],str[100003];
    scanf("%d",&t);
    while(t--)
    {
        int n,m;
        scanf("%d%d",&n,&m);
        for(int i=1; i<=n; i++)
            scanf("%d",&a[i]);
        for(int i=1; i<=m; i++)
        {
            scanf("%d%d",&po[i].pos,&po[i].pre);
            po[i].id=i;
        }
        sort(po+1,po+m+1,cmp);
        int top=0,sum=0,num=0;//top记录最高位
        for(int i=1; i<=m; i++)//计算从1到修改地方摘的苹果数
        {
            while(num<po[i].pos)
            {
                if(a[num]>top)//num
                {
                    sum++;
                    top=a[num];
                }
                num++;
            }
            if(po[i].pre>top)
                ans[po[i].id]=sum+1;//如果修改的值比最大的值大,就摘下这个苹果
            if(po[i].pre<=top)
            {
                ans[po[i].id]=sum;//否则就不摘,将修改地方的高度变成最高的高度
                po[i].pre=top;
            }
        }
        num=n;
        top=0;
        for(int i=m; i>=1; i--)
        {
            while(num>po[i].pos)
            {
                while(top!=0&&a[str[top]]<=a[num])//如果原来可摘的苹果比它前面的苹果低就不摘,踢出队列
                    top--;
                if(top==0)
                    dp[num]=1;
                else
                    dp[num]=dp[str[top]]+1;
                str[++top]=num;//str数组存的修改地方后面可以摘的苹果的编号
                num--;
            }
            int l=1,r=top,mid,res=0;
            while(l<=r)//二分找出比修改后的大的最小值res
            {
                mid=(l+r)/2;
                if(a[str[mid]]>po[i].pre)
                {
                    l=mid+1;
                    res=str[mid];
                }
                else
                    r=mid-1;
            }
            ans[po[i].id]+=dp[res];//加上找到的res后可摘的苹果数量
        }
        for(int i=1; i<=m; i++)
            printf("%d\n",ans[i]);
    }
    return 0;
}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值