Bzoj4553: [Tjoi2016&Heoi2016]序列

题面

传送门

Sol

处理出每个数\(p[i]\)最大能变成多少和最小能变成多少\(mx[i], mn[i]\)

\(f[i]\)表示到第\(i\)个位置的最长的满足要求的序列
\(f[i]=max(f[j])+1\)满足\(mx[j]\le p[i]\)\(p[j] \le mn[i]\)

然后这个东西类似三维偏序,可以在线树套树维护
或者\(CDQ\)分治来搞

\(CDQ\)分治时,可以先把左边按\(p\)从小到大排序,右边按\(mn\)
然后双端点移动,树状数组统计

注意分治完左边后不能立刻分治右边,必须按照中序遍历,做完这一层再分治右边
因为这一层的\(DP\)值会对右边产生影响
还要注意\(DP\)值要取\(max\)
这个很显然然而没取\(WA\)了一遍

# include <bits/stdc++.h>
# define RG register
# define IL inline
# define Fill(a, b) memset(a, b, sizeof(a))
using namespace std;
const int _(1e5 + 5);
typedef long long ll;

IL int Input(){
    RG int x = 0, z = 1; RG char c = getchar();
    for(; c < '0' || c > '9'; c = getchar()) z = c == '-' ? -1 : 1;
    for(; c >= '0' && c <= '9'; c = getchar()) x = (x << 1) + (x << 3) + (c ^ 48);
    return x * z;
}

int n, m, f[_], ans, mx[_];
struct Point{
	int id, p, mn, mx;
} p[_];

IL void Add(RG int x, RG int v){
	for(; x <= n; x += x & -x) mx[x] = max(mx[x], v);
}

IL void Cls(RG int x){
	for(; x <= n; x += x & -x) mx[x] = 0;
}

IL int Query(RG int x){
	RG int ret = 0;
	for(; x; x -= x & -x) ret = max(ret, mx[x]);
	return ret;
}

IL int Cmp1(RG Point A, RG Point B){
	return A.id < B.id;
}

IL int Cmp2(RG Point A, RG Point B){
	return A.p < B.p;
}

IL int Cmp3(RG Point A, RG Point B){
	return A.mn < B.mn;
}

IL void CDQ(RG int l, RG int r){
	if(l == r) return;
	RG int mid = (l + r) >> 1;
	CDQ(l, mid);
	sort(p + l, p + mid + 1, Cmp2), sort(p + mid + 1, p + r + 1, Cmp3);
	for(RG int i = mid + 1, j = l; i <= r; ++i){
		while(p[j].p <= p[i].mn && j <= mid) Add(p[j].mx, f[p[j].id]), ++j;
		f[p[i].id] = max(f[p[i].id], Query(p[i].p) + 1);
	}
	for(RG int i = l; i <= mid; ++i) Cls(p[i].mx);
	sort(p + mid + 1, p + r + 1, Cmp1), CDQ(mid + 1, r);
}

int main(RG int argc, RG char* argv[]){
	n = Input(), m = Input();
	for(RG int i = 1; i <= n; ++i)
		f[i] = 1, p[i].id = i, p[i].p = p[i].mx = p[i].mn = Input();
	for(RG int i = 1; i <= m; ++i){
		RG int x = Input(), y = Input();
		p[x].mn = min(p[x].mn, y), p[x].mx = max(p[x].mx, y);
	}
	CDQ(1, n);
	for(RG int i = 1; i <= n; ++i) ans = max(ans, f[i]);
	printf("%d\n", ans);
    return 0;
}
posted @ 2018-04-03 10:39  Cyhlnj  阅读(122)  评论(0编辑  收藏  举报