<CDQ分治> 序列 [HYSBZ - 4553]

F - 序列 HYSBZ - 4553

\(n, m\)分别表示序列的长度和变化的个数。

接下来一行有\(n\)个数,表示这个数列原始的状态

接下来\(m\)行,每行有2个数\(x, y\),表示数列的第\(x\)项可以变化成\(y\)这个值

最多使用一种变化, 求在所有可能的情况下都非减的最长子序列的长度

\(1 <= x <= n\) 所有数字均为正整数,且小于等于\(100,000\)

Sample Input

3 4 1 2 3 1 2 2 3 2 1 3 4

Sample Output

3

题解

一开始看错题意了,注意在所有可能情况下都是非减

\(lea[i],big[i]\)分别为\(i\)最小和最大的变动

合法子序列中任意两相邻的\(i,j\)满足\(big[i]\leq a[j] \&\&a[i]\leq lea[j]\)

那么将左区间以\(big\)排序,右区间以\(a\)排序,再用树状数组维护\(a和lea\)即可

#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <algorithm>

using namespace std;
typedef long long LL;
const int MAXN = 1e5 + 10;
const LL INF  = 2147483647;

inline int in()
{
    int x = 0, flag = 1; char ch = getchar();
    while (ch < '0' || ch > '9') { if (ch == '-') flag = -1; ch = getchar(); }
    while (ch >= '0' && ch <= '9') x = (x << 3) + (x << 1) + (ch ^ 48), ch = getchar();
    return x * flag;
}

int n, m;
int f[MAXN];

struct Fenwick
{
    int va[MAXN];
    void dec(int pos)
        {
             for (int i = pos; i <= 100000; i += (i & (-i))) va[i] = 0;
        }
    void upd(int pos, int v)
        {
            if (va[pos] >= v) return;
            va[pos] = v;
            for (int i = pos; i <= 100000; i += (i & (-i))) va[i] = max(va[i], v);
        }
    int qry(int x)
        {
            int ret = -1;
            for (int i = x; i > 0; i &= (i - 1)) ret = max(ret, va[i]);
            return ret;
        }
} T;

struct Node
{
    int val, lea, big, id;
} a[MAXN], b[MAXN];
bool cmpv(Node x, Node y) { return x.val < y.val; }
bool cmpb(Node x, Node y) { return x.big < y.big; }
bool cmpi(Node x, Node y) { return x.id < y.id; }
void solve(int l, int r)
{
    if (l >= r) return ;
    int mid = (l + r) >> 1;
    solve(l, mid);
    sort(a + l, a + mid + 1, cmpb);
    sort(a + mid + 1, a + r + 1, cmpv);
    int i = l, j = mid + 1, k = l;
    while (k <= r)
    {
        k ++;
        if (j > r || (i <= mid && a[i].big <= a[j].val))
        {
            T.upd(a[i].val, f[a[i].id]);
            i ++;
        }
        else
        {
            f[a[j].id] = max(f[a[j].id], T.qry(a[j].lea) + 1);
            j ++;
        }
    }
    for (int i = l; i <= mid; i ++) T.dec(a[i].val);
    sort(a + mid + 1, a + r + 1, cmpi); 
    solve(mid + 1, r);
}

int main()
{
    n = in(); m = in();

    for (int i = 1; i <= n; i ++) a[i].val = a[i].lea = a[i].big = in(), a[i].id = i, f[i] = 1;
    for (int i = 1; i <= m; i ++)
    {
        int id = in(), va = in();
        a[id].lea = min(a[id].lea, va);
        a[id].big = max(a[id].big, va);
    }
    solve(1, n);
    int ans = -1;
    for (int i = 1; i <= n; i ++) ans = max(ans, f[i]);
    printf("%d\n", ans);
    return 0;
}
/*
 */

转载于:https://www.cnblogs.com/ikihsiguoyr/p/10569530.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值