• 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
    ", ans);
        return 0;
    }
    
  • 相关阅读:
    java多线程
    java垃圾回收
    java研发常见问题总结 1
    js获取时间加多山天和时间戳转换成日期
    php时间选择器亲测可以自己修改
    html5时间选择器
    php生成员工编号,产品编号
    桌面远程链接
    SQL 左外连接查询 将右表中的多行变为左表的一列或多列
    PHPMailer发匿名邮件及Extension missing: openssl的解决
  • 原文地址:https://www.cnblogs.com/cjoieryl/p/8706944.html
Copyright © 2020-2023  润新知