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;
}