bzoj4553【TJOI2016&HEOI2016】序列

4553: [Tjoi2016&Heoi2016]序列

Time Limit: 20 Sec  Memory Limit: 128 MB
Submit: 260  Solved: 133
[Submit][Status][Discuss]

Description

 佳媛姐姐過生日的時候,她的小夥伴從某寶上買了一個有趣的玩具送給他。玩具上有一個數列,數列中某些項的值

可能會變化,但同一個時刻最多隻有一個值發生變化。現在佳媛姐姐已經研究出了所有變化的可能性,她想請教你
,能否選出一個子序列,使得在任意一種變化中,這個子序列都是不降的?請你告訴她這個子序列的最長長度即可
。注意:每種變化最多隻有一個值發生變化。在樣例輸入1中,所有的變化是:
1 2 3
2 2 3
1 3 3
1 1 31 2 4
選擇子序列爲原序列,即在任意一種變化中均爲不降子序列在樣例輸入2中,所有的變化是:3 3 33 2 3選擇子序列
爲第一個元素和第三個元素,或者第二個元素和第三個元素,均可滿足要求

Input

 輸入的第一行有兩個正整數n, m,分別表示序列的長度和變化的個數。接下來一行有n個數,表示這個數列原始的

狀態。接下來m行,每行有2個數x, y,表示數列的第x項可以變化成y這個值。1 <= x <= n。所有數字均爲正整數
,且小於等於100,000

Output

 一個整數

Sample Input

3 4
1 2 3
1 2
2 3
2 1
3 4

Sample Output

3



動態規劃+CDQ分治

每種變化只有一個只發生變化,所以每個位置i只有最大值mx[i]和最小值mn[i]有用。

DP方程:f[i]=max{f[j]}+1,其中j<i,a[j]≤mn[i]且mx[j]≤a[i]。

用CDQ分治優化DP。最初的時候所有編號是遞增的,然後每次計算左邊對右邊影響的時候,讓左面的a值有序,右面的mn值有序,這樣就滿足了前兩個條件,第三個條件mx[j]≤a[i]用一個樹狀數組維護。每次計算完之後按照a值歸併排序。

注意,遞歸到每一層的順序是:處理左邊→計算左邊對右邊的影響→處理右邊。




#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<cstring>
#include<algorithm>
#define F(i,j,n) for(int i=j;i<=n;i++)
#define D(i,j,n) for(int i=j;i>=n;i--)
#define ll long long
#define N 100005
using namespace std;
int n,m,ans,f[N],s[N];
struct data{int v,mn,mx,id;}a[N],t[N];
inline int read()
{
	int x=0,f=1;char ch=getchar();
	while (ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();}
	while (ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
	return x*f;
}
inline bool cmpmn(data a,data b){return a.mn<b.mn;}
inline bool cmpid(data a,data b){return a.id<b.id;}
inline int query(int x)
{
	int ret=0;
	for(;x;x-=(x&(-x))) ret=max(ret,s[x]);
	return ret;
}
inline void change(int x,int y){for(;x<=100000;x+=(x&(-x))) s[x]=max(s[x],y);}
inline void clear(int x){for(;x<=100000;x+=(x&(-x))) s[x]=0;}
void solve(int l,int r)
{
	if (l>=r) return;
	int mid=(l+r)>>1;
	solve(l,mid);
	sort(a+mid+1,a+r+1,cmpmn);
	int tmp=l;
	F(i,mid+1,r)
	{
		while (tmp<=mid&&a[tmp].v<=a[i].mn) change(a[tmp].mx,f[a[tmp].id]),tmp++;
		f[a[i].id]=max(f[a[i].id],query(a[i].v)+1);
	}
	F(i,l,tmp-1) clear(a[i].mx);
	sort(a+mid+1,a+r+1,cmpid);
	solve(mid+1,r);
	int l1=l,l2=mid+1;tmp=l;
	while (l1<=mid&&l2<=r) t[tmp++]=a[l1].v<a[l2].v?a[l1++]:a[l2++];
	while (l1<=mid) t[tmp++]=a[l1++];
	while (l2<=r) t[tmp++]=a[l2++];
	F(i,l,r) a[i]=t[i];
}
int main()
{
	n=read();m=read();
	F(i,1,n) a[i].v=a[i].mn=a[i].mx=read(),a[i].id=i,f[i]=1;
	F(i,1,m){int x=read(),y=read();a[x].mn=min(a[x].mn,y);a[x].mx=max(a[x].mx,y);}
	solve(1,n);
	F(i,1,n) ans=max(ans,f[i]);
	printf("%d\n",ans);
	return 0;
}


發佈了417 篇原創文章 · 獲贊 21 · 訪問量 82萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章