《P4093 [HEOI2016/TJOI2016] 序列》

题目描述

佳媛姐姐过生日的时候,她的小伙伴从某宝上买了一个有趣的玩具送给她。

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

输入格式

输入的第一行有两个正整数 n,m,分别表示序列的长度和变化的个数。

接下来一行有 n 个整数,表示这个数列原始的状态。

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

输出格式

输出一个整数,表示对应的答案。

输入输出样例

输入 #1复制

复制代码
3 4 
1 2 3 
1 2 
2 3 
2 1 
3 4

输出 #1复制

复制代码
3

说明/提示

注意:每种变化最多只有一个值发生变化。

在样例输入中,所有的变化是:

复制代码
1 2 3
2 2 3
1 3 3
1 1 3
1 2 4

选择子序列为原序列,即在任意一种变化中均为不降子序列。

对于 20% 数据,所有数均为正整数,且小于等于 300。

对于 50% 数据,所有数均为正整数,且小于等于 3000。

对于 100% 数据,所有数均为正整数,且小于等于 105。1≤x≤n。

代码实现:

cpp 复制代码
#include <bits/stdc++.h>
using namespace std;

#define Int register int
#define MAXN 100005

int n, m;

class BIT
{
private:
    int tr[MAXN];
    int lowbit(int &x) { return x & (-x); }
public:
    void clear(int pos) { for (Int i = pos; i <= n; i += lowbit(i)) tr[i] = 0; }
    void upd(int pos, int x) { for (Int i = pos; i <= n; i += lowbit(i)) tr[i] = max(tr[i], x); }
    int qry(int pos) { int res = 0; for (Int i = pos; i; i -= lowbit(i)) res = max(res, tr[i]); return res; }
} tree;

struct nd
{
    int val, minv, maxv, id; // 原权值、最小权值、最大权值、编号
} a[MAXN];

int dp[MAXN];

bool cmp_val(nd A, nd B) { return A.val < B.val; }
bool cmp_min(nd A, nd B) { return A.minv < B.minv; }
bool cmp_id(nd A, nd B) { return A.id < B.id; }

void cdq(int l, int r)
{
    if (l == r) return;
    int mid = (l + r) >> 1;
    cdq(l, mid);
    sort(a + l, a + mid + 1, cmp_val);
    sort(a + mid + 1, a + r + 1, cmp_min);
    int i = l, j = mid + 1;
    for (; j <= r; ++j)
    {
        while (i <= mid && a[i].val <= a[j].minv) tree.upd(a[i].maxv, dp[a[i].id]), i++;
        dp[a[j].id] = max(dp[a[j].id], tree.qry(a[j].val) + 1);
    }
    while (i > l) tree.clear(a[--i].maxv);
    sort(a + mid + 1, a + r + 1, cmp_id);
    cdq(mid + 1, r);
}

int rd()
{
    int x = 0; char c = getchar(); int f = 1;
    while (c < '0' || c > '9') { if (c == '-') f = -f; c = getchar(); }
    while (c >= '0' && c <= '9') { x = (x << 3) + (x << 1) + c - '0'; c = getchar(); }
    return x * f;
}

void wt(int x)
{
    if (x < 0) { x = -x; putchar('-'); }
    if (x > 9) wt(x / 10);
    putchar(x % 10 + '0');
}

signed main()
{
    n = rd(), m = rd();
    for (Int i = 1; i <= n; ++i) a[i].val = a[i].minv = a[i].maxv = rd(), a[i].id = i;
    for (Int i = 1; i <= m; ++i)
    {
        int x = rd(), y = rd();
        a[x].minv = min(a[x].minv, y);
        a[x].maxv = max(a[x].maxv, y);
    }
    for (Int i = 1; i <= n; ++i) dp[i] = 1;
    cdq(1, n);
    int max_res = 0;
    for (Int i = 1; i <= n; ++i) max_res = max(max_res, dp[i]);
    wt(max_res), putchar('\n');
    return 0;
}
相关推荐
Jasmine_llq4 天前
《P4587 [FJOI2016] 神秘数》
算法·倍增思想·稀疏表(st 表)·前缀和数组(解决静态区间和查询·st表核心实现高效预处理和查询·预处理优化(提前计算所需信息·快速io提升大规模数据读写效率