HDU-6406 Taotao Picks Apples

版权声明:选经典题目,写精品文章. https://blog.csdn.net/nka_kun/article/details/81736253

                                                                               Taotao Picks Apples

                                                          Time Limit: 2000/2000 MS (Java/Others) 


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

题意:n个苹果都有高度,遇到上升的苹果必须取,每次询问改变一个高度,问改变后一共可取多少,询问不相关.

思路:分情况讨论,之前没有取的苹果改变高度后,要么取,并且影响后面的苹果取,二分即可,要不不取,没影响.

之前取的苹果,高度升高后,影响后面的苹果取,还是二分,高度降低后,可能能多取几个,这个时候需要我们提前记录取的苹果之间的上升序列,这个时候就能派上用场,看看这个上升序列中第一个比max(这个苹果前面最大值,这个苹果新高度)大的位置在哪,就阔以了.

代码:

#include<bits/stdc++.h>
#define mem(a,b) memset(a,b,sizeof(a))
using namespace std;
typedef long long ll;
const int inf = 0x3f3f3f3f;
const int maxn = 2e5+5;

int n,m;
int h[maxn],pm[maxn],take[maxn],b[maxn],pre[maxn],sum;//pm记录前面最大值 ,pre记录此位置前一个取的苹果 
vector<int> a[maxn];									//b记录取的苹果 ,a记录取的苹果间的上升序列 

void pre_init()
{
	int maxh = 0,lastm = 0,now = 0;
	for(int i = 1;i<= n;i++)
	{
		pm[i] = maxh;
		if(h[i]> maxh)
		{
			take[i] = 1;
			maxh = h[i];
			lastm = 0;
			now = i;
			b[++sum] = h[i];
		}
		else if(h[i]> lastm)
		{
			a[now].push_back(h[i]);
			lastm = h[i];
		}
		pre[i] = sum;
	}
	return ;
}

int query(int l,int r,int v)
{
	while(l<= r)
	{
		int mid = (l+r)>>1;
		if(b[mid]<= v)
			l = mid+1;
		else
			r = mid-1;
	}
	return l;
}

int inquire(int x,int y)
{
	int l = 0,r = a[x].size()-1;
	while(l<= r)
	{
		int mid = (l+r)>>1;
		if(a[x][mid]<= y)
			l = mid+1;
		else
			r = mid-1;
	}
	return a[x].size()-l;
}

int modify(int x,int y)
{
	if(take[x] == 0)
	{
		if(y<= pm[x]) return sum;
		else return sum-(query(pre[x]+1,sum,y)-(pre[x]+1))+1;
	}
	else
	{
		if(y>= h[x])
			return sum-(query(pre[x]+1,sum,y)-(pre[x]+1));
		else
			return y> pm[x]?sum+inquire(x,max(y,pm[x])):sum+inquire(x,max(y,pm[x]))-1;
	}
}

void init()
{
	sum = 0;
	mem(take,0);
	for(int i = 1;i<= n;i++) a[i].clear();
}

int main()
{
	int t;
	cin>>t;
	
	while(t--)
	{
		scanf("%d %d",&n,&m);
		init();
		for(int i = 1;i<= n;i++)
			scanf("%d",&h[i]);
		pre_init();
		
		while(m--)
		{
			int p,q;
			scanf("%d %d",&p,&q);
			
			printf("%d\n",modify(p,q));
		}	
	}

	return 0;
}

猜你喜欢

转载自blog.csdn.net/nka_kun/article/details/81736253