1. 程式人生 > >【BZOJ4553】[Tjoi2016&Heoi2016]序列 cdq分治+樹狀數組

【BZOJ4553】[Tjoi2016&Heoi2016]序列 cdq分治+樹狀數組

ios 生日 oid ring ostream 等於 namespace 教你 rip

【BZOJ4553】[Tjoi2016&Heoi2016]序列

Description

佳媛姐姐過生日的時候,她的小夥伴從某寶上買了一個有趣的玩具送給他。玩具上有一個數列,數列中某些項的值可能會變化,但同一個時刻最多只有一個值發生變化。現在佳媛姐姐已經研究出了所有變化的可能性,她想請教你,能否選出一個子序列,使得在任意一種變化中,這個子序列都是不降的?請你告訴她這個子序列的最長長度即可。註意:每種變化最多只有一個值發生變化。在樣例輸入1中,所有的變化是:

1 2 3 2 2 3 1 3 3 1 1 3 1 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

題解:我們設每個數可能的最大值為R,最小值為L,初始值為V,那麽我們選出的序列的相鄰兩項一定滿足:Ra<=Vb且Va<=Lb。顯然是個類似三維偏序的東西,cdq分治+樹狀數組維護即可。

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
int n,m,N,now,ans;
const int maxn=100010;
int s[maxn],tim[maxn];
struct node
{
	int l,r,v,org,f;
}p[maxn];
bool cmpr(const node &a,const node &b)
{
	return a.r<b.r;
}
bool cmpv(const node &a,const node &b)
{
	return a.v<b.v;
}
bool cmpo(const node &a,const node &b)
{
	return a.org<b.org;
}
inline int rd()
{
	int ret=0,f=1;	char gc=getchar();
	while(gc<‘0‘||gc>‘9‘)	{if(gc==‘-‘)	f=-f;	gc=getchar();}
	while(gc>=‘0‘&&gc<=‘9‘)	ret=ret*10+(gc^‘0‘),gc=getchar();
	return ret*f;
}
inline void updata(int x,int val)
{
	for(int i=x;i<=N;i+=i&-i)
	{
		if(tim[i]<now)	tim[i]=now,s[i]=0;
		s[i]=max(s[i],val);
	}
}
inline int query(int x)
{
	int i,ret=0;
	for(i=x;i;i-=i&-i)
	{
		if(tim[i]<now)	tim[i]=now,s[i]=0;
		ret=max(ret,s[i]);
	}
	return ret;
}
void solve(int l,int r)
{
	if(l==r)	return ;
	int mid=(l+r)>>1,i,h1=l,h2=mid+1;
	sort(p+l,p+r+1,cmpo);
	solve(l,mid);
	sort(p+l,p+mid+1,cmpr),sort(p+mid+1,p+r+1,cmpv);
	now++;
	for(i=l;i<=r;i++)
	{
		if(h1<=mid&&(h2>r||p[h1].r<=p[h2].v))	updata(p[h1].v,p[h1].f),h1++;
		else	p[h2].f=max(p[h2].f,query(p[h2].l)+1),h2++;
	}
	solve(mid+1,r);
}
int main()
{
	n=rd(),m=rd();
	int i,a,b;
	for(i=1;i<=n;i++)	p[i].v=p[i].l=p[i].r=rd(),N=max(N,p[i].v),p[i].org=i,p[i].f=1;
	for(i=1;i<=m;i++)	a=rd(),b=rd(),p[a].l=min(p[a].l,b),p[a].r=max(p[a].r,b),N=max(N,b);
	solve(1,n);
	for(i=1;i<=n;i++)	ans=max(ans,p[i].f);
	printf("%d",ans);
	return 0;
}

【BZOJ4553】[Tjoi2016&Heoi2016]序列 cdq分治+樹狀數組