hdu 6406 Taotao Picks Apples (2018 Multi-University Training Contest 8 1010)(二分,前缀和)

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.

Statistic | Submit | Clarifications | Back

【题意】

有n个高度不同的苹果,拿走第一个苹果之后,从前往后遍历,每当碰到一个苹果,如果其高度比上一个“被拿走的苹果”高的话,就将其拿走。

有q次询问,每次询问给两个参数p,c  表示将原来(所有n个苹果中)第p个苹果的高度更改为 c,输出此时n个苹果中总共可以被拿走多少个苹果?

【分析】

这道题可以分情况讨论:

设原来苹果的高度都存在a[1]....a[n] 下面我们一起分析一下第p个苹果高度更改为c之后的答案

首先我们要预处理一下前缀和 : ans[i]表示前i个苹果被拿走的数量

还要记录前面被拿走的苹果高度最大值,即最后一个被拿走苹果的高度

maxx[i]记录到i位置拿的最后一个苹果的高度

1、c>a[p] (高度变大了)

如果c>maxx[i-1] ,则该苹果会被拿走 ,更改之后 目前到i位置总共会被拿走的苹果数量应该是ans[i-1]+1.那么i之后会被拿走的苹果数量呢?

我们思考一下可以发现,a[p]变大之后,可能会使原本后面可以拿的苹果数量变少,但是剩下那些可以被拿走的一定原来也是可以被拿走的。因此我们在预处理时还要将原本被拿走的苹果存入一个数组b(用vector),b数组一定是递增的。现在我们只需要二分查找b数组中大于c的苹果有多少个就可以了。upper_bound(b,b+cnt,c) - b 是小于c的数量,用总数量减去它就是该苹果后面会被拿走的苹果数量。

如果c<=maxx[i-1] 既然a[p]增大了以后都不大于maxx[i-1] 那么之前肯定也小于,所以这颗苹果始终没被拿,没影响,直接输出ans[n];

2、c<a[p] (高度变小了)

如果c>maxx[i-1] 则这颗苹果始终会被拿走, 到i位置会被拿走的苹果数量为ans[i-1]+1;现在我们一起分析一下i之后会被拿走的苹果数量 (重点,难点) 如果a[p]位置的高度变小,有可能会使后面被拿走的苹果数量增加,也就是使后面一些苹果,他们的高度介于c到a[p]之间,且高度递增的一些苹果,原本不能拿走,现在可以被拿走了。那我们如何找到这些苹果呢? 答案是提前预处理。

用一个二维的数组v(vector)  v[i]这一行表示当到i位置的最大值(即到i为止最后一个被拿走的苹果)减小时,可能会被拿走的苹果。(我们思考一下会知道这些苹果的高度介于最大值与第二大值之间),然后在该情况下我们只要去v[p]这一行找大于c的苹果的数量即可,即 v[p].size()  -(upper_bound(v[p].begin(),v[p].end(),c)-v[p].begin())。

如果c<maxx[i-1]  则这颗苹果不会被拿走了,但是其之前可能会被拿走也可能不会,这个需要讨论!!!。我们可以知道现在到i为止可以被拿走的苹果的数量是ans[i-1],  那其之后会被拿走的苹果数量呢?

如果a[p] == maxx[p]&&a[p]!=maxx[p-1] 则之前被拿走了 ,现在不会被拿走了,则后面可以多拿的苹果数量就是v[p].size();

我们也可以写成 v[p].size()  -(upper_bound(v[p].begin(),v[p].end(),c)-v[p].begin())这样写代码的时候可以和上面那种情况合并了

否则,如果之间没被拿走,那不会有影响,直接输出ans[n]

【代码】

#include<bits/stdc++.h>
using namespace std;
const int M = 1e5+10;
struct node{
    int id,val;
};
vector<int>v[M];
int a[M],ans[M],maxx[M],b[M];

int main()
{
    int t,n,q,p,c;
    scanf("%d",&t);
    while(t--){
        scanf("%d%d",&n,&q);
        for(int i = 1;i <= n;i ++){
            scanf("%d",&a[i]);
        }
        node mx,mx1;//mx记录最后被拿的苹果(最大值),mx1维护当前第二大值(不一定是倒数第二拿的苹果,可能位于最大值之后)
        mx.val = 0; mx1.val = 0,mx.id = 0,mx1.id = 0;
        int cnt = 0,num = 0;//num记录被拿苹果总数量
        maxx[0] = 0;
        for(int i = 1;i <= n;i ++){
            if(mx.val < a[i]){
                mx1.val = mx.val; mx1.id = mx.id;
                mx.val = a[i]; mx.id = i; b[cnt++] = a[i];//b数组记录了所有被拿的苹果
                num++;
            }
            else if(mx1.val < a[i]){
                mx1.val = a[i]; mx1.id = i;
                v[mx.id].push_back(a[i]);//v[i]这一行存的是当“当前最大值”变小,会被拿的苹果
            }
            maxx[i] = mx.val;  ans[i] = num;//maxx[i]记录到i位置拿的最后一个苹果的价值
            //ans[i]维护前缀和
        }
        while(q--){
            scanf("%d%d",&p,&c);
            int sum = 0;
            if(c > a[p]){
                if(c > maxx[p-1]){
                sum ++;  sum += ans[p-1];
                int kk =  upper_bound(b,b+cnt,c) - b;
                if(kk != cnt) sum += cnt-kk;
                }
                else
                    sum = ans[n];
            }
            else if(c == a[p])  sum = ans[n];
            else//变小了(重点)
            {
                if(c > maxx[p-1]) sum++,sum += ans[p-1];
                else sum += ans[p-1];
                if(a[p] == maxx[p]&&a[p]!=maxx[p-1]){
                int kk = upper_bound(v[p].begin(),v[p].end(),c)-v[p].begin();
                sum += v[p].size()- kk;
                int kk1 =  upper_bound(b,b+cnt,a[p]) - b;
                if(kk1 != cnt)  sum += cnt-kk1;
                }
                else
                sum = ans[n];
            }
            printf("%d\n",sum);
        }
        for(int i = 0;i <= n;i ++){
            maxx[i] = 0; ans[i] = 0; v[i].clear();
        }
        for(int i = 0;i <= cnt;i ++)  b[i] = 0;
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/Destinymiao/article/details/81736201
今日推荐