链接: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;
}