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;
}
时间: 2024-12-13 09:49:05

bzoj4553【TJOI2016&HEOI2016】序列的相关文章

BZOJ4553: [Tjoi2016&amp;Heoi2016]序列 树套树优化DP

把pos[i]上出现的平常值定义为nor[i]最大值定义为max[i]最小值定义为min[i],那么我们发现在两个值,i(前),j(后),当且仅当max[i]<=nor[j],nor[i]<=min[j]时才会组成序列的前后两个值,并且当序列里所有连续的两个值都满足这个条件是时就可以,因此我们以f[i]表示以i为起点的序列最长值,那么我们就可以转移了f[i]=maxf[j](max[i]<=nor[j],nor[i]<=min[j],pos[i]<pos[j])+1,这就是一

BZOJ4553: [Tjoi2016&amp;Heoi2016]序列

Description 佳媛姐姐过生日的时候,她的小伙伴从某宝上买了一个有趣的玩具送给他.玩具上有一个数列,数列中某些项的值 可能会变化,但同一个时刻最多只有一个值发生变化.现在佳媛姐姐已经研究出了所有变化的可能性,她想请教你 ,能否选出一个子序列,使得在任意一种变化中,这个子序列都是不降的?请你告诉她这个子序列的最长长度即可 .注意:每种变化最多只有一个值发生变化.在样例输入1中,所有的变化是: 1 2 3 2 2 3 1 3 3 1 1 31 2 4 选择子序列为原序列,即在任意一种变化中均

【BZOJ4553】[Tjoi2016&amp;Heoi2016]序列 cdq分治+树状数组

[BZOJ4553][Tjoi2016&Heoi2016]序列 Description 佳媛姐姐过生日的时候,她的小伙伴从某宝上买了一个有趣的玩具送给他.玩具上有一个数列,数列中某些项的值可能会变化,但同一个时刻最多只有一个值发生变化.现在佳媛姐姐已经研究出了所有变化的可能性,她想请教你,能否选出一个子序列,使得在任意一种变化中,这个子序列都是不降的?请你告诉她这个子序列的最长长度即可.注意:每种变化最多只有一个值发生变化.在样例输入1中,所有的变化是: 1 2 3 2 2 3 1 3 3 1

BZOJ 4553 Tjoi2016&amp;Heoi2016 序列

Tjoi2016&Heoi2016序列 Description 佳媛姐姐过生日的时候,她的小伙伴从某宝上买了一个有趣的玩具送给他.玩具上有一个数列,数列中某些项的值 可能会变化,但同一个时刻最多只有一个值发生变化.现在佳媛姐姐已经研究出了所有变化的可能性,她想请教你 ,能否选出一个子序列,使得在任意一种变化中,这个子序列都是不降的?请你告诉她这个子序列的最长长度即可 .注意:每种变化最多只有一个值发生变化.在样例输入1中,所有的变化是: 1 2 3 2 2 3 1 3 3 1 1 31 2 4

[BZOJ4553][HEOI2016]序列 CDQ分治

4553: [Tjoi2016&Heoi2016]序列 Time Limit: 20 Sec  Memory Limit: 128 MB Description 佳媛姐姐过生日的时候,她的小伙伴从某宝上买了一个有趣的玩具送给他.玩具上有一个数列,数列中某些项的值 可能会变化,但同一个时刻最多只有一个值发生变化.现在佳媛姐姐已经研究出了所有变化的可能性,她想请教你 ,能否选出一个子序列,使得在任意一种变化中,这个子序列都是不降的?请你告诉她这个子序列的最长长度即可 .注意:每种变化最多只有一个值发

bzoj4552【TJOI2016&amp;HEOI2016】排序

4552: [Tjoi2016&Heoi2016]排序 Time Limit: 60 Sec  Memory Limit: 256 MB Submit: 291  Solved: 171 [Submit][Status][Discuss] Description 在2016年,佳媛姐姐喜欢上了数字序列.因而他经常研究关于序列的一些奇奇怪怪的问题,现在他在研究一个难题 ,需要你来帮助他.这个难题是这样子的:给出一个1到n的全排列,现在对这个全排列序列进行m次局部排序,排 序分为两种:1:(0,l,

4552: [Tjoi2016&amp;Heoi2016]排序

4552: [Tjoi2016&Heoi2016]排序 Description 在2016年,佳媛姐姐喜欢上了数字序列.因而他经常研究关于序列的一些奇奇怪怪的问题,现在他在研究一个难题 ,需要你来帮助他.这个难题是这样子的:给出一个1到n的全排列,现在对这个全排列序列进行m次局部排序,排 序分为两种:1:(0,l,r)表示将区间[l,r]的数字升序排序2:(1,l,r)表示将区间[l,r]的数字降序排序最后询问第q 位置上的数字. Input 输入数据的第一行为两个整数n和m.n表示序列的长度,

[BZOJ] 4552: [Tjoi2016&amp;Heoi2016]排序 #二分+线段树+算法设计策略

4552: [Tjoi2016&Heoi2016]排序 Time Limit: 60 Sec  Memory Limit: 256 MBSubmit: 1451  Solved: 734[Submit][Status][Discuss] Description 在2016年,佳媛姐姐喜欢上了数字序列.因而他经常研究关于序列的一些奇奇怪怪的问题,现在他在研究一个难题 ,需要你来帮助他.这个难题是这样子的:给出一个1到n的全排列,现在对这个全排列序列进行m次局部排序,排 序分为两种:1:(0,l,r

bzoj4551[Tjoi2016&amp;Heoi2016]树

bzoj4551[Tjoi2016&Heoi2016]树 题意: 给个根节点为1的n点树,初始时节点1标记,Q个操作,每次可以标记一个点或求一个点最近一个标记了的祖先. 题解: 链剖可以写,当正解应该是并查集.离线读入所有操作,累加每个节点的标记次数,之后所有未被标记的节点向其父亲节点连边,然后倒着来,如果操作是询问则输出这个节点在并查集中的根节点,如果是标记则将该节点的标记数减1,一旦这个节点的标记数减到了0,就让它向父亲节点连边. 代码: 1 #include <cstdio> 2