Taotao Picks Apples

本文探讨了一种基于高度贪心选择苹果的策略,通过维护一个上升序列来解答修改序列后能选择的苹果数量的问题。文章详细介绍了算法的实现过程,包括使用队列维护序列、处理更新点对序列的影响以及应对不同查询情况的方法。

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

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

Problem Description

There is an apple tree in front of Taotao's house. When autumn comes, n apples on the tree ripen, and Taotao will go to pick these apples.

When Taotao picks apples, Taotao scans these apples from the first one to the last one. If the current apple is the first apple, or it is strictly higher than the previously picked one, then Taotao will pick this apple; otherwise, he will not pick.

Given the heights of these apples h1,h2,⋯,hn , you are required to answer some independent queries. Each query is two integers p,q , which asks the number of apples Taotao would pick, if the height of the p -th apple were q (instead of hp ). Can you answer all these queries?

 

 

Input

The first line of input is a single line of integer T (1≤T≤10) , the number of test cases.

Each test case begins with a line of two integers n,m (1≤n,m≤105) , denoting the number of apples and the number of queries. It is then followed by a single line of n integers h1,h2,⋯,hn (1≤hi≤109) , denoting the heights of the apples. The next m lines give the queries. Each of these m lines contains two integers p (1≤p≤n) and q (1≤q≤109) , as described in the problem statement.

 

 

Output

For each query, display the answer in a single line.

 

 

Sample Input

 

1 5 3 1 2 3 4 4 1 5 5 5 2 3

 

 

Sample Output

 
1 5 3

Hint

For the first query, the heights of the apples were 5, 2, 3, 4, 4, so Taotao would only pick the first apple. For the second query, the heights of the apples were 1, 2, 3, 4, 5, so Taotao would pick all these five apples. For the third query, the heights of the apples were 1, 3, 3, 4, 4, so Taotao would pick the first, the second and the fourth apples.

题意:

给一个序列,每次贪心选取比前一个数大的数。每次询问修改一个数,求修改后的序列的能选出 多少个数。询问不叠加。
 

分析:

我用的队列维护上升序列,然后看更新的点是否对队列中的数产生影响,或者对没有加入队列的数产生影响

代码:

#include<bits/stdc++.h>
#define ll long long
using namespace std;
int a[100005],b[100005];
int num[100005];///0到i中有一个出现在队列
int R[100005];
int vis[100005];///上一个在队列的位置
int f[100005];
stack<int>q;
int main()
{
    int t,i,j,n,m,k,x,y,l,r,mid,maxn,cnt;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d%d",&n,&k);
        cnt=1;
        for(i=1;i<=n;i++)
        {
            scanf("%d",&a[i]);
            if(i==1)
                f[cnt]=i,b[cnt++]=a[i],vis[1]=1;
            else
            if(a[i]>b[cnt-1])
            {
                f[cnt]=i;
                b[cnt++]=a[i],vis[i]=i;
            }
            else
            {
                vis[i]=vis[i-1];
            }
            num[i]=cnt-1;
        }
        while(!q.empty())q.pop();
        for(i=n;i>0;i--)
        {
            while(!q.empty()&&q.top()<=a[i])
                q.pop();
            q.push(a[i]);
            R[i]=q.size();///从这一点严格上升到n的长度
        }
        while(k--)
        {
            scanf("%d%d",&x,&y);
            if(a[x]>y)    ///变小
            {
                if(vis[x]!=x)///不在队列中,不产生影响
                printf("%d\n",cnt-1);
                else
                {   ///在队列中,变小之后可能会将非队列中的数加入队列
                    maxn=num[x]-1;
                    if(num[x]-1>0&&b[num[x]-1]>=y)///变小的数是否小于前一个队列中的数,如果小于离开队列
                    {
                        for(l=x+1;l<=n;l++){
                            if(a[l]>b[num[x]-1])
                            {
                                maxn+=R[l];
                                break;
                            }
                        }
                        printf("%d\n",maxn);
                        continue;
                    }
                    else
                    {
                        maxn++;
                        for(l=x+1;l<=n;l++){
                            if(a[l]>y)
                            {
                                maxn+=R[l];
                                break;
                            }
                        }
                        printf("%d\n",maxn);
                    }
                }
            }
            else
            if(a[x]==y)
            printf("%d\n",cnt-1);
            else    ///变大
            {
                if(vis[x]==x){///变大之前在队列,变化后一定在队列,但是会将后面的部分队列元素踢出
                l=upper_bound(b+1,b+cnt,y)-b;
                printf("%d\n",cnt-l+num[x]);
                }
                else
                if(num[x]>0&&b[num[x]]>=y)///变大之前不在队列,变化之后也不会在队列,不产生影响
                printf("%d\n",cnt-1);
                else
                {   ///变大之后加入队列,并且踢出队列中的某些数
                    l=upper_bound(b+1,b+cnt,y)-b;
                    printf("%d\n",cnt-l+num[x]+1);
                }
            }
        }
    }
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值