HDU-6406多校第八场 前缀+二分+单调队列

链接:http://hdu.hustoj.com/showproblem.php?pid=6406

Taotao Picks Apples

Time Limit: 2000/2000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others)
Total Submission(s): 370    Accepted Submission(s): 94


 

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

题意:修改一个值,从头开始遍历,最大值被覆盖了多少次。

由于每次询问都是不叠加的,我们可以预处理前缀的最大值以及最大值被覆盖的次数。

对所有的询问做离线处理。对修改的位置进行降序,对原数组倒着做一次单调队列维护一个后缀,如果该位置的值内修改了,那就再单调队列里面二分找后面第一个大于修改值的位置。不知道这么说,看代码注释吧。。

#include<bits/stdc++.h>
#include <cstdio>
using namespace std;
typedef long long LL;
const int maxn=1e5+5;
int a[maxn];
int q[maxn],b[maxn];
int h[maxn],que[maxn];
int ol[maxn];
struct node{
    int p,v,id;
    bool friend operator<(node a,node b)
    {
        return a.p>b.p;
    }
}ask[maxn];
int bin(int l,int r,int val)
{
    int mid,ans=-1;
    while ( l<=r )
    {
        mid=l+r>>1;
        if( a[que[mid]]>val )
        {
            ans=que[mid], l=mid+1;
        }
        else r=mid-1;
    }
    return ans;
}
int main()
{
    int T;
    scanf( "%d", &T );
    while ( T-- )
    {
        int n,m;
        scanf( "%d%d", &n, &m );
        q[0]=b[0]=0;
        for(int i=1;i<=n;i++)
        {
            scanf( "%d", &a[i] );
            q[i]=q[i-1];   // 前缀被覆盖的次数
            b[i]=b[i-1];   // 前缀最大值
            if( a[i]>b[i-1] )
            {
                q[i]++;
                b[i]=a[i];
            }
        }
        for(int i=0;i<m;i++)
        {
            scanf( "%d%d", &ask[i].p, &ask[i].v );
            ask[i].id=i;
        }
        sort(ask,ask+m);
        int tail=0,head=1;
        int pos=0;
        for(int i=n;i>0;i--)
        {
            while( ask[pos].p==i ) // 当前位置要修改
            {
                int k=q[i-1];
                int ans=b[i-1];  // 记录这个位置之前的最大值以及次数
                if( ans<ask[pos].v )
                {
                    k++;
                    ans=ask[pos].v;
                }
                int pp=bin(head,tail,ans); // 在单调队列中找第一个大于val的位置
                if( pp!=-1 )  // 找到了,加上一个后缀。
                {
                    k+=h[pp];
                }
                ol[ask[pos].id]=k;
                pos++;
            }
            while( head<=tail&&a[que[tail]]<=a[i] ) tail--;
            que[++tail]=i;   
            h[i]=tail-head+1;  // 队列中的个数就是后缀覆盖的次数
                         // 从i到末尾最大值覆盖了几次
        }
        for(int i=0;i<m;i++)
            printf( "%d\n", ol[i] );
    }
    return 0;
}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值