Embiid  

「TJOI / HEOI2016」序列

题意:

玩具上有一个数列,数列中某些项的值可能会变化,但同一个时刻最多只有一个值发生变化。现在佳媛姐姐已经研究出了所有变化的可能性,她想请教你,能否选出一个子序列,使得在任意一种变化中,这个子序列都是不降的?请你告诉她这个子序列的最长长度即可。

解法:

我们可以预处理处每个点最大可能变成的值\(r_i\),最小可能变成的值\(l_i\),显然,如果一个子序列符合要求,那么必然有\(r_{i-1}\leq a_i和a_{i-1}\leq l_i\)
所以我们很容易写出转移方程\(f_i=\max_{j=1}^{i-1} (f[j]+1)\) , 如果 \(r_j\leq a_i,a_j\leq l_i\)

方法1

很显然,我们可以把限制条件看成二维点对,用树套树维护最大值即可。
我写了线段树套线段树TLE了,后来改成树状数组就过了。代码在最后会附上。

方法2

加上j<i这一条件,我们易想到三维偏序问题,考虑cdq来解决,这个常数会比树套树小。
首先,由于限制的条件不同于一般的三位偏序,我们考虑lmid对mid+1r的答案影响时,我们不像归并那样一个个插入,我们每次分治lr时,都将lmid按r要素排序,mid+1~r按a要素排序,对于某个\(r_i>a_j\),这以后的i对于j的答案就没有影响了,用树状数组找出答案就行了。
此外,考虑到每个\(f_i\)的最优值需要所有小于i的pos最优值都已经求出来,所以我们需要先处理左半边,在处理自己,最后处理右边。

线段树套线段树

#include <bits/stdc++.h>
#define lson rt << 1
#define rson rt << 1 | 1
using namespace std;
const int maxn = 1e5;

int f[maxn + 11],a[maxn + 11],l[maxn + 11],r[maxn + 11];
int tree[200 * maxn + 11],ls[200 * maxn + 11],rs[200 * maxn + 11];
int root[4 * maxn + 11];
int tot = 0;
int m;

void push_up(int rt) { tree[rt] = max(tree[ls[rt]] , tree[rs[rt]]); }
void update(int &rt,int l,int r,int pos,int val) {
	if (l > pos || r < pos) return;
	if (!rt) rt = ++tot;
	if (l == r) { tree[rt] = max(tree[rt] , val); return; }
	int mid = (l + r) >> 1;
	update(ls[rt] , l , mid , pos , val);
	update(rs[rt] , mid + 1 , r , pos , val);
	push_up(rt);
}

void update(int rt,int l,int r,int x,int y,int val) {
	if (l > x || r < x) return;
	update(root[rt] , 1 , m , y , val);
	if (l == r) return;
	int mid = (l + r) >> 1;
	update(lson , l , mid , x , y , val);
	update(rson , mid + 1 , r , x , y, val);
}

int query(int rt,int l,int r,int al,int ar) {
	if (l > ar || r < al || !rt) return 0;
	if (l >= al && r <= ar) return tree[rt];
	int mid = (l + r) >> 1;
	return max(query(ls[rt] , l , mid , al , ar) , query(rs[rt] , mid + 1 , r , al , ar));
}

int query(int rt,int l,int r,int xl,int xr,int yl,int yr) {
	if (l > xr || r < xl) return 0;
	if (l >= xl && r <= xr) return query(root[rt] , 1 , m , yl , yr);
	int mid = (l + r) >> 1;
	return max(query(lson , l , mid , xl , xr , yl , yr) , query(rson , mid + 1 , r , xl , xr , yl , yr));
}

int main() {
	int n;
	scanf("%d %d",&n,&m);
	int mx = 0;
	for (int i = 1; i <= n; i++) { 
		scanf("%d" , &a[i]);
		l[i] = r[i] = a[i];
		mx = max(mx , a[i]);
	} 
	for (int i = 1; i <= m; i++) { 
		int x,y;
		scanf("%d %d",&x,&y);
		l[x] = min(l[x] , y);
		r[x] = max(r[x] , y);
		mx = max(mx , y);
	} 
	m = mx;
	for (int i = 1; i <= n; i++) {
		f[i] = query(1 , 1 , m , 1 , a[i] , 1 , l[i]) + 1;
		update(1 , 1 , m , r[i] , a[i] , f[i]);
	} 
	printf("%d\n" , tree[1]);
} 

树状数组套线段树

#include <bits/stdc++.h>
#define lson rt << 1
#define rson rt << 1 | 1
using namespace std;
const int maxn = 1e5;

int tot = 0;
int f[maxn + 11],a[maxn + 11],l[maxn + 11],r[maxn + 11],root[maxn + 11];
int tree[200 * maxn + 11],rs[200 * maxn + 11],ls[200 * maxn + 11];
int m;

void update(int &rt,int l,int r,int pos,int val) {
	if (l > pos || r < pos) return;
	if (!rt) rt = ++tot;
	tree[rt] = max(tree[rt] , val);
	if (l == r) return;
	int mid = (l + r) >> 1;
	update(ls[rt] , l , mid , pos , val);
	update(rs[rt] , mid + 1 , r , pos , val);
}

int query(int rt,int l,int r,int al,int ar) {
	if (l > ar || r < al || !rt) return 0;
	if (l >= al && r <= ar) return tree[rt];
	int mid = (l + r) >> 1;
	return max(query(ls[rt] , l , mid , al , ar) , query(rs[rt] , mid + 1 , r , al , ar));
}

int main() { 
	int n;
	scanf("%d %d",&n,&m);
	int mx = 0;
	for (int i = 1; i <= n; i++) { 
		scanf("%d" , &a[i]);
		l[i] = r[i] = a[i];
		mx = max(mx , a[i]);
	} 
	for (int i = 1; i <= m; i++) { 
		int x,y;
		scanf("%d %d",&x,&y);
		l[x] = min(l[x] , y);
		r[x] = max(r[x] , y);
		mx = max(mx , y);
	} 
	m = mx;
	int ans = 0;
	for (int i = 1; i <= n; i++) { 
		mx = 0;
		for (int j = a[i]; j; j -= (j & (-j))) mx = max(mx , query(root[j] , 1 , m , 1 , l[i]));
		f[i] = mx + 1;
		for (int j = r[i]; j <= m; j += (j & (-j))) update(root[j] , 1 , m , a[i] , f[i]);
		ans = max(ans , f[i]);
	} 
	printf("%d\n" , ans);
} 

cdq分治

#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e5;
int m;
int bit[maxn + 11],ans[maxn + 11];
struct node {
	int a,l,r,i;
}p[maxn + 11];

bool cmpr(node x,node y) { return x.r < y.r; }
bool cmpa(node x,node y) { return x.a < y.a; }
bool cmpi(node x,node y) { return x.i < y.i; }
int lowbit(int x) { return x & (-x); }
void update(int x,int val) { for (; x <= m; x += lowbit(x)) bit[x] = max(bit[x] , val); }
void clear(int x) { for (; x <= m; x += lowbit(x)) bit[x] = 0; }
int query(int x) { int ans = 0; for (; x ; x -= lowbit(x)) ans = max(ans , bit[x]); return ans; }

void cdq(int l,int r) {
	if (l >= r) return;
	int mid = (l + r) >> 1;
	cdq(l , mid);
	sort(p + l , p + mid + 1 , cmpr);
	sort(p + mid + 1 , p + r + 1 , cmpa);
	int i,j;
	for (i = l , j = mid + 1; i <= mid && j <= r;) { 
		if (p[i].r <= p[j].a) { update(p[i].a , ans[p[i].i]); i++; }
		else { ans[p[j].i] = max(ans[p[j].i] , 1 + query(p[j].l)); j++; }
	}
	for (; j <= r; j++) ans[p[j].i] = max(ans[p[j].i] , 1 + query(p[j].l));
	for (i--; i >= l; i--) clear(p[i].a);
	sort(p + mid + 1 , p + r + 1 , cmpi);
	cdq(mid + 1 , r);
}

int main(){
	int n;
	scanf("%d %d",&n,&m);
	int mx = 0;
	for (int i = 1; i <= n; i++) {
		scanf("%d",&p[i].a);
		p[i].l = p[i].r = p[i].a;
		p[i].i = i;
		mx = max(mx , p[i].a);
		ans[i] = 1;
	}
	for (int i = 1; i <= m; i++) {
		int x,y;
		scanf("%d %d",&x,&y);
		p[x].l = min(p[x].l , y);
		p[x].r = max(p[x].r , y);
		mx = max(mx , y);
	}
	m = mx;
	cdq(1 , n);
	mx = 0;
	for (int i = 1; i <= n; i++) mx = max(mx , ans[i]);
	printf("%d\n" , mx);
} 

posted on 2020-02-10 20:19  Embiid  阅读(259)  评论(1编辑  收藏  举报