【YbtOJ#20061】波动序列

题目

题目链接:http://noip.ybtoj.com.cn/contest/86/problem/3

思路

\(f[i][j][1/2/3/4]\) 表示前 \(i\) 个数,最后一个数选的是 \(j\),且最后一个数是在第一行 / 第二行 / 第三行升序 / 第三行降序的最大选中个数。
容易推出 \(O(nm)\) 转移。发现转移中对于每一个不同的列 \(i\),只有 \(4\) 个位置需要修改,所以开四棵线段树维护 dp 值即可。
每次转移只需要区间求 \(\max\),单点修改。时间复杂度 \(O(n\log n)\)

代码

#include <bits/stdc++.h>
using namespace std;

const int N=100010;
int n,m,a[4][N],b[N*3];

int read()
{
	int d=0,f=1; char ch=getchar();
	while (!isdigit(ch)) { if (ch=='-') f=-1; ch=getchar(); }
	while (isdigit(ch)) d=(d<<3)+(d<<1)+ch-48,ch=getchar();
	return d*f;
}

struct SegTree
{
	int maxn[N*12];	
	
	void update(int x,int l,int r,int k,int v)
	{
		maxn[x]=max(maxn[x],v);
		if (l==k && r==k) return;
		int mid=(l+r)>>1;
		if (k<=mid) update(x*2,l,mid,k,v);
			else update(x*2+1,mid+1,r,k,v);
	}
	
	int query(int x,int l,int r,int ql,int qr)
	{
		if (l==ql && r==qr) return maxn[x];
		int mid=(l+r)>>1;
		if (qr<=mid) return query(x*2,l,mid,ql,qr);
		if (ql>mid) return query(x*2+1,mid+1,r,ql,qr);
		return max(query(x*2,l,mid,ql,mid),query(x*2+1,mid+1,r,mid+1,qr));
	}
}seg1,seg2,seg3,seg4;

int Maxquery(int ql,int qr,bool f1,bool f2,bool f3,bool f4)
{
	int maxf=0;
	if (f1) maxf=max(maxf,seg1.query(1,1,m,ql,qr)+1);
	if (f2) maxf=max(maxf,seg2.query(1,1,m,ql,qr)+1);
	if (f3) maxf=max(maxf,seg3.query(1,1,m,ql,qr)+1);
	if (f4) maxf=max(maxf,seg4.query(1,1,m,ql,qr)+1);
	return maxf;
}

int main()
{
	freopen("sequence.in","r",stdin);
	freopen("sequence.out","w",stdout);
	n=read();
	for (int i=1;i<=3;i++)
		for (int j=1;j<=n;j++)
			b[++m]=a[i][j]=read();
	sort(b+1,b+1+m);
	m=unique(b+1,b+1+m)-b-1;
	for (int i=1;i<=3;i++)
		for (int j=1;j<=n;j++)
			a[i][j]=lower_bound(b+1,b+1+m,a[i][j])-b;
	for (int i=1;i<=n;i++)
	{
		int f1=Maxquery(1,a[1][i],1,1,1,1),f2=Maxquery(a[2][i],m,1,1,1,1);
		int f3=Maxquery(1,a[3][i],1,1,1,0),f4=Maxquery(a[3][i],m,1,1,0,1);
		seg1.update(1,1,m,a[1][i],max(f1,1)); seg2.update(1,1,m,a[2][i],max(f2,1));
		seg3.update(1,1,m,a[3][i],max(f3,1)); seg4.update(1,1,m,a[3][i],max(f4,1));
	}
	printf("%d",Maxquery(1,m,1,1,1,1)-1);
	return 0;
}
原文地址:https://www.cnblogs.com/stoorz/p/13809059.html