HDU - 6406 Taotao Picks Apples(線段樹區間合併)

題目鏈接:點擊查看

題目大意:給出一個長度爲 n 的數列 a,再給出 m 次詢問,每次詢問假設如果設置 a[ pos ] = val 的話,那麼此時序列中的最長上升子序列是多少,此時的上升子序列指的是:若選取 a[ 1 ] 後,找到下一個大於 a[ 1 ] 的位置記爲 a[ pos ] ,依次類推

題目分析:考察區間合併的一道題目,因爲這個題目對於最長上升子序列多加了一點限制,所以處理起來也並不是很複雜,假如現在有左區間和右區間需要合併,我們可以維護一下每個區間的最大值和貢獻,不難看出,左區間一定是有貢獻的,對於右區間來說還需要進一步討論:

  1. 如果右區間的最大值小於左區間的最大值,那麼右區間的貢獻爲 0
  2. 如果右區間的左子區間的最大值小於左區間的最大值,那麼左子區間的貢獻爲 0 ,向右子區間遞歸
  3. 如果右區間的左子區間的最大值大於左區間的最大值,那麼左子區間的貢獻繼續遞歸,此時右子區間的貢獻已經不由左區間控制了,可以直接加上,根據 pushup 函數中的關係,移項可以得出右子區間對於整個區間的貢獻

最後強調一下,上面第三種情況,右子區間對於整個區間的貢獻,並不能單純的以 cnt[ k<<1|1 ] 爲答案,因爲在 pushup 中的公式爲:cnt[ k ] = cnt[ k<<1 ] + cal() ,此處的 cal 函數計算的纔是右子區間對於整個區間的貢獻,所以通過移項可以得出,此時右子區間的貢獻爲 cnt[ k ] - cnt[ k<<1 ]

時間複雜度是雙 log 級別的,不過 n 只有 1e5 ,雙 log 的複雜度也是頂得住的

代碼:
 

#include<iostream>
#include<cstdio>
#include<string>
#include<ctime>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<stack>
#include<climits>
#include<queue>
#include<map>
#include<set>
#include<sstream>
#include<cassert>
using namespace std;

typedef long long LL;

typedef unsigned long long ull;

const int inf=0x3f3f3f3f;

const int N=1e5+100;

int a[N];

struct Node
{
	int l,r,mmax,cnt;
}tree[N<<2];

int cal(int k,int h)
{
	if(tree[k].mmax<=h)
		return 0;
	if(tree[k].l==tree[k].r)
		return tree[k].mmax>h;
	int mid=tree[k].l+tree[k].r>>1;
	if(tree[k<<1].mmax<=h)
		return cal(k<<1|1,h);
	else
		return cal(k<<1,h)+tree[k].cnt-tree[k<<1].cnt;
}

void pushup(int k)
{
	tree[k].mmax=max(tree[k<<1].mmax,tree[k<<1|1].mmax);
	tree[k].cnt=tree[k<<1].cnt+cal(k<<1|1,tree[k<<1].mmax);
}

void build(int k,int l,int r)
{
	tree[k].l=l;
	tree[k].r=r;
	if(l==r)
	{
		tree[k].mmax=a[l];
		tree[k].cnt=1;
		return;
	}
	int mid=l+r>>1;
	build(k<<1,l,mid);
	build(k<<1|1,mid+1,r);
	pushup(k);
}

void change(int k,int pos,int val)
{
	if(tree[k].l==tree[k].r)
	{
		tree[k].mmax=val;
		return;
	}
	int mid=tree[k].l+tree[k].r>>1;
	if(pos<=mid)
		change(k<<1,pos,val);
	else
		change(k<<1|1,pos,val);
	pushup(k);
}

int main()
{
#ifndef ONLINE_JUDGE
//  freopen("data.in.txt","r",stdin);
//  freopen("data.out.txt","w",stdout);
#endif
//  ios::sync_with_stdio(false);
	int w;
	cin>>w;
	while(w--)
	{
		int n,m;
		scanf("%d%d",&n,&m);
		for(int i=1;i<=n;i++)
			scanf("%d",a+i);
		build(1,1,n);
		while(m--)
		{
			int pos,val;
			scanf("%d%d",&pos,&val);
			change(1,pos,val);
			printf("%d\n",tree[1].cnt);
			change(1,pos,a[pos]);
		}
	}

















    return 0;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章