BZOJ4553: [Tjoi2016&Heoi2016]序列

4553: [Tjoi2016&Heoi2016]序列

Time Limit: 20 Sec Memory Limit: 128 MB
Submit: 1150 Solved: 527
[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

题解

\(minV[i]\)表示\(i\)这个位置出现过的最小值
\(maxV[i]\)表示\(i\)这个位置出现过的最大值
裸的dp方程:\(dp[i] = max(dp[j] + 1), if\ a[j] <= minV[i], a[i] >= maxV[j]\)
右边这个东西是个经典的二维数点问题,无穷多的做法
CDQ分治/树套树/.....
线段树套线段树被卡爆空间
卡了半天终于卡过了

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <algorithm>
#include <queue>
#include <vector>
#include <map>
#include <string> 
#include <cmath> 
#include <sstream>
inline int lowbit(int x){return x & -x;}
inline int max(int a, int b){return a > b ? a : b;}
inline int min(int a, int b){return a < b ? a : b;}
inline void read(int &x)
{
    x = 0;char ch = getchar(), c = ch;
    while(ch < '0' || ch > '9') c = ch, ch = getchar();
    while(ch <= '9' && ch >= '0') x = x * 10 + ch - '0', ch = getchar();
    if(c == '-') x = -x;
}
const int INF = 0x3f3f3f3f;
const int MAXN = 160000 + 10;
int n,m,num[MAXN],maxV[MAXN],minV[MAXN],ma;
//X为num  Y为maxV 

int dp[MAXN], dataY[MAXN << 6], ans, ls[MAXN << 6], rs[MAXN << 6], root[MAXN << 2], tot;
int newnode(){return ++ tot;}
void modifyY(int p, int k, int &o, int l = 1, int r = ma)
{
	if(!o) o = newnode(); 
	dataY[o] = max(dataY[o], k);
	if(l == r) return;
	int mid = (l + r) >> 1;
	if(p <= mid) modifyY(p, k, ls[o], l, mid);
	else modifyY(p, k, rs[o], mid + 1, r);
	return;
}
void modifyX(int x, int y, int k, int o = 1, int l = 1, int r = ma)
{
	modifyY(y, k, root[o]);
	if(l == r) return;
	int mid = (l + r) >> 1;
	if(x <= mid) modifyX(x, y, k, o << 1, l, mid);
	else modifyX(x, y, k, o << 1 | 1,mid + 1, r);
}
int askY(int y1, int y2, int o, int l = 1, int r = ma)
{
	if(!o) return 0;
	if(y1 <= l && y2 >= r) return dataY[o];
	int mid = (l + r) >> 1, ans = 0;
	if(mid >= y1) ans = max(ans, askY(y1, y2, ls[o], l, mid));
	if(mid < y2) ans = max(ans, askY(y1, y2, rs[o], mid + 1, r));
	return ans;
}
int askX(int x1, int x2, int y1, int y2, int o = 1, int l = 1, int r = ma)
{
	if(x1 <= l && x2 >= r) return askY(y1, y2, root[o]);
	int mid = (l + r) >> 1, ans = 0;
	if(mid >= x1) ans = max(ans, askX(x1, x2, y1, y2, o << 1, l, mid));
	if(mid < x2) ans = max(ans, askX(x1, x2, y1, y2, o << 1 | 1, mid + 1, r));
	return ans;	
}
void modify(int x)
{
	modifyX(maxV[x], num[x], dp[x]);
}
int ask(int x)
{
	return askX(1, num[x], 1, minV[x]);
}

int main()
{
	read(n), read(m);
	for(int i = 1;i <= n;++ i) read(num[i]), maxV[i] = minV[i] = num[i], ma = max(ma, num[i]);
	for(int i = 1;i <= m;++ i)
	{
		int tmp1,tmp2;
		read(tmp1), read(tmp2);
		maxV[tmp1] = max(maxV[tmp1], tmp2);
		minV[tmp1] = min(minV[tmp1], tmp2);
		ma = max(ma, tmp2);
	}
	for(int i = 1;i <= n;++ i)
		dp[i] = ask(i) + 1, modify(i), ans = max(ans, dp[i]);
	printf("%d", ans);
	return 0;
}
posted @ 2018-02-27 14:54  嘒彼小星  阅读(174)  评论(0编辑  收藏  举报