Taotao Picks Apples HDU - 6406

版权声明:欢迎大家指正错误,有不同观点的欢迎评论,共同进步 https://blog.csdn.net/Sirius_han/article/details/82146672

K - Taotao Picks Apples

题目链接:HDU - 6406

题意:树上有一排苹果,每个苹果又同的高度,taotao要摘苹果,而且必须从第一个苹果开始摘,然后没遇到一个高度比之前摘得苹果高的苹果就摘下来,问taota能摘多少苹果,第一个苹果必须摘;每次改变一个苹果高度,然后输出能摘到的苹果个数;每次都只在原来基础上改变苹果高度;

思路:看似是个LIS,但是每个数是变化的,这种操作有一般就要想到线段树;但是线段树要维护什么值呢?区间最大值肯定要维护了;在一个就是满足条件的区间LIS;

区域区间最大值:tr[m].max=max(tr[m<<1].max, tr[m<<1|1].max);这一点是毫无疑问的,重点是LIS怎么维护???怎么合并???

father的LIS必定是>=左son的LIS;那么右son的LIS要不要加上呢?

1:如果右son的区间第一个数>左son的max,那么一定加上右son的LIS;

2:如果右son的max<=左son的max,那么一定不加右son的LIS;

3:同时不满足以上两点:现在咋办呢?

      此时,可以将右son再分为左右son,如果左左son的max>左son的max就加上右son的LIS-左左son的LIS,为啥嘞?因为,右son的LIS的区间中有减去左左son的LIS一定是满足题意的;然后再递归找左左son;;;反之说明右右son中的LIS一定不能被加,递归左左son;

#include <bits/stdc++.h>
using namespace std;
const int maxn=1e5+10;
int h[maxn];
struct node{
	int l, r, mx, len;
}tr[maxn<<2];
int cal(int x, int m){
	if(tr[m].l==tr[m].r) return tr[m].mx>x;
	if(x>=tr[m<<1].mx) return cal(x, m<<1|1);
	else return tr[m].len-tr[m<<1].len+cal(x, m<<1);
}
void pushup(int m){
	tr[m].mx=max(tr[m<<1].mx, tr[m<<1|1].mx);
	tr[m].len=tr[m<<1].len+cal(tr[m<<1].mx, m<<1|1);
}
void build(int m, int l, int r){
	tr[m].l=l;
	tr[m].r=r;
	if(l==r){
		tr[m].mx=h[l];
		tr[m].len=1;
		return;
	}
	int mid=(l+r)>>1;
	build(m<<1, l, mid);
	build(m<<1|1, mid+1, r);
	pushup(m);
}
void updata(int m, int x, int val){
	if(tr[m].l==x&&tr[m].r==x){
		tr[m].mx=val;
		return;
	}
	int mid=(tr[m].l+tr[m].r)>>1;
	if(x<=mid) updata(m<<1, x, val);
	else updata(m<<1|1, x, val);
	pushup(m);
}

int main(){
	int T;
	scanf("%d", &T);
	while(T--){
		int n, m;
		scanf("%d%d", &n, &m);
		for(int i=1; i<=n; i++){
			scanf("%d", &h[i]);
		}
		build(1, 1, n);
		while(m--){
			int x, y;
			scanf("%d%d", &x, &y);
			updata(1, x, y);
			printf("%d\n", tr[1].len);
			updata(1, x, h[x]);//每次都在原基础上修改,所以要再改回来;
		}
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/Sirius_han/article/details/82146672