zoukankan      html  css  js  c++  java
  • 「TJOI / HEOI2016」序列

    「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_jleq a_i,a_jleq 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
    " , 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
    " , 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
    " , mx);
    } 
    

  • 相关阅读:
    关于migration build failed的问题
    C盘无损扩容(傻逼拯救者128G固态分两个盘)
    .NET Core:搭建私有Nuget服务器以及打包发布Nuget包
    VMware下的Centos7联网并设置固定IP(nat)
    使用docker compose 构建多个镜像
    centos 安装docker-compose
    使用使用dockerfile构建webapi镜像然后使用link和bridge两种方式进行桥接
    docker 安装mysql 并将文件挂载到本地
    Conetos 下安装docker 和镜像加速
    docker 一些命令
  • 原文地址:https://www.cnblogs.com/Embiid/p/12292527.html
Copyright © 2011-2022 走看看