codeforces 650D (树状数组)

题目链接:点击这里

题意:动态LIS,改变一个值求LIS。

先把询问离线下来按照改变的位置排序,把所有的数字离散化。首先先用树状数组求出每一位为结尾的最长上升前缀f[i]和每一位开始的最长上升后缀g[i],然后考虑每一个数字改变后的LIS情况,分成两种讨论:

  • LIS不包含这个数。这种情况比较简单,考虑是不是每一个LIS都含有这个数字即可,也即对于所有的LIS,某一位必须是这个数。所以直接统计每一个数字在LIS中的位置,然后判断这个位置是否唯一即可。

  • LIS包含这个数。对于一个数a[i],显然需要找到一个j和k使得 aj<ai<aki<j<k ,直接正反扫两遍用树状数组统计即可。

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#pragma comment(linker, "/STACK:102400000,102400000")
#define Clear(x,y) memset (x,y,sizeof(x))
#define Close() ios::sync_with_stdio(0)
#define Open() freopen ("more.in", "r", stdin)
#define get_min(a,b) a = min (a, b)
#define get_max(a,b) a = max (a, b);
#define y0 yzz
#define y1 yzzz
#define fi first
#define se second
#define pii pair
#define pli pair
#define pll pair
#define pb push_back
#define pl c<<1
#define pr (c<<1)|1
#define lson tree[c].l,tree[c].mid,pl
#define rson tree[c].mid+1,tree[c].r,pr
#define mod 1000000007
typedef unsigned long long ull;
template <class T> inline T lowbit (T x) {return x&(-x);}
template <class T> inline T sqr (T x) {return x*x;}
template <class T>
inline bool scan (T &ret) {
    char c;
    int sgn;
    if (c = getchar(), c == EOF) return 0; //EOF
    while (c != '-' && (c < '0' || c > '9') ) c = getchar();
    sgn = (c == '-') ? -1 : 1;
    ret = (c == '-') ? 0 : (c - '0');
    while (c = getchar(), c >= '0' && c <= '9') ret = ret * 10 + (c - '0');
    ret *= sgn;
    return 1;
}
const double pi = 3.14159265358979323846264338327950288L;
using namespace std;
#define INF 1e8
#define maxn 800005
#define maxm 1000005
//-----------------morejarphone--------------------//

int n, m, cnt;
vector <int> num;
int a[maxn];
struct Q {
    int pos, num, id;
    bool operator < (const Q &a) const {
        return pos < a.pos;
    }
} qu[maxn];
int f[maxn], g[maxn];
int c[maxn];

void add1 (int x, int num) {
    for (int i = x; i < maxn; i += lowbit (i)) get_max (c[i], num);
}
int query1 (int x) {
    int ans = 0;
    for (int i = x; i > 0; i -= lowbit (i)) get_max (ans, c[i]);
    return ans;
}
void add2 (int x, int num) {
    for (int i = x; i > 0; i -= lowbit (i)) get_max (c[i], num);
}
int query2 (int x) {
    int ans = 0;
    for (int i = x; i < maxn; i += lowbit (i)) get_max (ans, c[i]);
    return ans;
}

int LIS;//LIS的长度
void init () {
    Clear (c, 0);
    for (int i = 1; i <= n; i++) {
        f[i] = query1 (a[i]-1)+1;
        add1 (a[i], f[i]);
    }
    Clear (c, 0);
    for (int i = n; i >= 1; i--) {
        g[i] = query2 (a[i]+1)+1;
        add2 (a[i], g[i]);
    }
    LIS = 0;
    for (int i = 1; i <= n; i++) get_max (LIS, f[i]+g[i]-1);
}

void lisanhua () {
    sort (num.begin (), num.end ());
    num.erase (unique (num.begin (), num.end ()), num.end ());
    cnt = num.size ();
    for (int i = 1; i <= n; i++) 
        a[i] = lower_bound (num.begin (), num.end (), a[i])-num.begin ()+1;
    for (int i = 1; i <= m; i++)
        qu[i].num = lower_bound (num.begin (), num.end (), qu[i].num)-num.begin ()+1;
}

int ans1[maxn];//不包含每一个数的LIS
int tmp[maxn];
void solve1 () {
    Clear (tmp, 0);
    for (int i = 1; i <= n; i++) if (f[i]+g[i]-1 == LIS) {
        tmp[f[i]]++;
    }
    for (int i = 1; i <= n; i++) {
        if (f[i]+g[i]-1 == LIS && tmp[f[i]] == 1) ans1[i] = LIS-1;
        else ans1[i] = LIS;
    }
}

//包含每一个改变值的LIS
int ans[maxn];//最后的答案
int l[maxn], r[maxn];//左边比他小的最长 右边比他大的最长
void solve2 () {
    Clear (c, 0);
    int pos = 1;
    for (int i = 1; i <= m; i++) {
        while (pos < qu[i].pos) {
            add1 (a[pos], f[pos]);
            pos++;
        }
        l[i] = query1 (qu[i].num-1);
    }
    Clear (c, 0);
    pos = n;
    for (int i = m; i >= 1; i--) {
        while (pos > qu[i].pos) {
            add2 (a[pos], g[pos]);
            pos--;
        }
        r[i] = query2 (qu[i].num+1);
    }
    for (int i = 1; i <= m; i++) {
        ans[qu[i].id] = ans1[qu[i].pos];
        get_max (ans[qu[i].id], l[i]+r[i]+1);
    }
}

int main () {
    scanf ("%d%d", &n, &m);
    num.clear ();
    for (int i = 1; i <= n; i++) {
        scan (a[i]);
        num.pb (a[i]);
    }
    for (int i = 1; i <= m; i++) {
        scanf ("%d%d", &qu[i].pos, &qu[i].num);
        num.pb (qu[i].num);
        qu[i].id = i;
    }
    sort (qu+1, qu+1+m);
    lisanhua ();
    init ();
    solve1 ();
    solve2 ();
    for (int i = 1; i <= m; i++) {
        printf ("%d\n", ans[i]);
    }
    return 0;
}
/*
15 1
76 9 32 82 40 91 46 5 12 69 44 97 30 13 29
2 62
6 3
7 10 6 9 5 8
1 1
6 9
4 11
*/

你可能感兴趣的:(树状数组)