欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Taotao Picks Apples HDU - 6406

程序员文章站 2022-05-27 15:21:27
...

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