2018 Multi-University Training Contest 8 1010 Taotao Picks Apples(hdu 6406)(ST、dp、二分)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/yz467796454/article/details/81711360

题目链接:hdu 6406 Taotao Picks Apples

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.

题意:n个苹果有不同的高度,现在从第一个苹果开始拿(第一个必拿),后面一旦遇到比前一个苹果高的苹果就拿(必拿),m个询问,每次修改某个苹果的高度,问最多拿几个苹果,修改不叠加。

思路: 因为修改是不叠加的,所以只需要预处理原来的高度。

具体看代码中的注释

#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<iostream>
#include<queue>
#include<set>
#define inf 0x3f3f3f3f
using namespace std;
const int maxn=100005;
int a[maxn];
int stmin[maxn][20];
int stmax[maxn][20];
int LOG[maxn];
int n,m;
//st[i][j]表示[i,i+2^j-1]的最值 
void Init(){
	int i,j;
	for(i=1;i<=n;i++)
		stmin[i][0]=stmax[i][0]=a[i];
	for(i=1;(1<<i)<=n;i++){ 
		for(j=1;j+(1<<i)-1<=n;j++){
			//stmin[j][i]=min(stmin[j][i-1],stmin[j+(1<<(i-1))][i-1]);
			stmax[j][i]=max(stmax[j][i-1],stmax[j+(1<<(i-1))][i-1]);
		}
	}
	LOG[2]=1;
	for(int i=3;i<maxn;i++){
		LOG[i]=LOG[i>>1]+1;
	}
}
int Query(int l,int r){//区间[l,r]的最大值 
	int k=(int)(LOG[r-l+1]/LOG[2]);
	return max(stmax[l][k],stmax[r-(1<<k)+1][k]);
	//return min(stmin[l][k],stmin[r-(1<<k)+1][k]);
}
int firstbig(int pos,int val){//pos右边第一个大于val的下标 
	int l=pos+1,r=n+1;
	while(l<r){
		int mid=(l+r)/2;
		if(Query(pos+1,mid)<=val)l=mid+1;//严格大,所以取到等号 
		else r=mid;
	}
	return l;
}
int dp[maxn];//从i开始最多能往后走几步 
int prebig[maxn];//1到i-1的最大值下标
int num[maxn];//1到i能够摘的最多苹果数 
int flag[maxn];//i是不是0到i的最大值 
void pre(){
	dp[n+1]=0;
	for(int i=n;i>=1;i--){
		dp[i]=dp[firstbig(i,a[i])]+1;
	}
	prebig[1]=0;
	num[1]=1;
	flag[1]=1;
	int prepos=1;
	int prenum=a[1];
	int cnt=1;
	for(int i=2;i<=n;i++){
		prebig[i]=prepos;
		if(a[i]>prenum){
			flag[i]=1;
			prenum=a[i];
			prepos=i;
			cnt++;
		}
		else{
			flag[i]=0;
		}
		num[i]=cnt;
	}
}
int main(){
	int t;
	scanf("%d",&t);
	while(t--){
		scanf("%d%d",&n,&m);
		for(int i=1;i<=n;i++){
			scanf("%d",&a[i]);
		}
		Init();
		pre();
		while(m--){
			int pos,x;
			scanf("%d%d",&pos,&x);
			if(flag[pos]){//修改的点是1到pos的最大值 
				if(pos==1){//修改的是第一个苹果的高度 
					printf("%d\n",dp[firstbig(1,x)]+1);
					 //+1是因为 dp[firstbig(1,x)]没有包括第一个苹果 
				}
				else{
					if(x<=a[prebig[pos]]){//修改后的点小于等于前一个最大值 
						int num1=num[prebig[pos]];//1到pos-1拿到的苹果数
						int p=firstbig(pos,a[prebig[pos]]);//前一个最大值右边第一个比它大的位置 
						printf("%d\n",num1+dp[p]);
					}
					else{//修改后的点大于前一个最大值 
						int num1=num[pos];
						int p=firstbig(pos,x);
						printf("%d\n",num1+dp[p]);
					} 
				}
			}
			else{//修改的点不是1到pos的最大值 
				if(x<=a[prebig[pos]]){//修改后还是小于等于前一个最大值,这时对答案不会有影响 
					printf("%d\n",num[n]);
				}
				else{//修改后的点大于前一个最大值 
					int num1=num[prebig[pos]]+1;//1到pos-1拿到的苹果数,再拿上当前的这个苹果 
					int p=firstbig(pos,x);
					printf("%d\n",num1+dp[p]);
				}
			}
		}
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/yz467796454/article/details/81711360
今日推荐