1. 程式人生 > >JZOJ-senior-5920. 【NOIP2018模擬10.22】風箏

JZOJ-senior-5920. 【NOIP2018模擬10.22】風箏

Time Limits: 4000 ms Memory Limits: 524288 KB

Description

當一陣風吹來,風箏飛上天空,為了你,而祈禱,而祝福,而感動……

oyiya 在 AK 了 IOI 之後來到了鄉下,在田野中玩耍,放鬆身心。

他發現前面有一排小朋友在放風箏,每一個風箏有一個高度 hi,風箏的高度可能會隨著小朋友的心情而改變。這時,毒瘤的 oyiya 有了一個毒瘤的 idea,他想知道改變高度之後風箏的最長嚴格上升子序列。oyiya 太強了表示並不想做這種水題,你能解決這個問題嗎?

Input

第一行為兩個整數 n, m,表示小朋友的個數和詢問數。

第二行有 n 個整數,表示 hi。

接下來 m 行,每行兩個整數 ai, bi,表示詢問將第 ai 只風箏的高度變成 bi 後的 LIS。注意詢問之間是獨立的,後面的詢問不受前面詢問的影響.

Output

m 行,每行一個整數表示詢問的答案。

Sample Input

3 3 2 2 3 1 3 1 1 3 2

Sample Output

2 3 1

Data Constraint

在這裡插入圖片描述

Solution

  • 題目要我們動態求出序列的LIS
  • 記原序列的LIS長度為 lenlen
  • 不難發現答案只有三種可能:len1lenlen+1len-1,len,len+1
  • 對於每次修改操作 xyx,y,我們將 yy 掛在 xx 位置上
  • 在求 f[i]f[i] (長度為 ii 的最長嚴格遞增子序列的末尾最小值)的時候順便將詢問拿出來
  • 求出若以它結尾從前往後最長長度 L[i]L[i] ,以及從後往前最長長度 R[i]R[i]
  • 我們考慮新序列的 LISLIS 的情況,它對於這個 yy 可以選或不選
  • 對於必選情況,顯然 ans=L[i]+R[i]1ans=L[i]+R[i]-1
  • 對於不選情況
  • 如果它出現在原序列的最長嚴格遞增子序列中而且最長嚴格遞增子序列只有必選它這一個,那麼ans=len1ans=len-1
  • 否則有別的位置可以使最長嚴格遞增子序列長度仍為 lenlen ,所以 ans=lenans=len
  • 如果它沒有出現在原序列的最長嚴格遞增子序列中,那麼 ans=lenans=len
  • 最終將幾種情況的答案取個 maxmax 就好啦

Code

#include<algorithm>
#include<cstring>
#include<cstdio>
#include<vector>

#define fo(i,a,b) for(int i=a;i<=b;++i)
#define fd(i,a,b) for(int i=a;i>=b;--i)

using namespace std;

const int N=5e5+5;
int n,m,t,lis;
int a[N],z[N],c[N],L[N],R[N],ans[N];
bool no[N];
struct node{int x,id;};
vector<node> V[N];
vector<int>Rank1[N],Rank2[N];

int main()
{
	freopen("kite.in","r",stdin);
	freopen("kite.out","w",stdout);
	scanf("%d%d",&n,&m);
	fo(i,1,n) scanf("%d",&a[i]);
	fo(i,1,m)
	{
		int x,y;
		scanf("%d%d",&x,&y);
		V[x].push_back((node){y,i});
	}
	
	t=0,memset(z,0,sizeof(z));
	fo(i,1,n)
	{
		if(V[i].size())
		{
			fo(j,0,V[i].size()-1)
			{
				int Rank=lower_bound(z+1,z+1+t,V[i][j].x)-z;
				Rank1[i].push_back(Rank);
			}
		}
		if(!t) z[++t]=a[i],L[i]=1;
		else
		{
			int x=lower_bound(z+1,z+1+t,a[i])-z;
			z[x]=a[i],t=max(t,x),L[i]=x;
		}
	}
	
	lis=t;
	
	t=0,memset(z,0,sizeof(z));
	fd(i,n,1)
	{
		if(V[i].size())
		{
			fo(j,0,V[i].size()-1)
			{
				int Rank=lower_bound(z+1,z+1+t,-V[i][j].x)-z;
				Rank2[i].push_back(Rank);
			}
		}
		if(!t) z[++t]=-a[i],R[i]=1;
		else
		{
			int x=lower_bound(z+1,z+1+t,-a[i])-z;
			z[x]=-a[i],t=max(t,x),R[i]=x;
		}
	}
	
	fo(i,1,n) if(L[i]+R[i]-1==lis) ++c[L[i]];
	fo(i,1,n) if(L[i]+R[i]-1==lis&&c[L[i]]>1) no[i]=1;
	
	fo(i,1,n) if(V[i].size())
		fo(j,0,V[i].size()-1)
		{
			int p=0;
			if(L[i]+R[i]-1==lis&&no[i]||L[i]+R[i]-1!=lis) p=lis; else p=lis-1;
			p=max(p,Rank1[i][j]+Rank2[i][j]-1);
			ans[V[i][j].id]=p;
		}
	fo(i,1,m) printf("%d\n",ans[i]);
}