codeforces 650D. Zip-line 线段树

题目链接

 

题目的意思很简单, 就是给你n个数, m个询问, 每次询问修改某一个位置的值, 然后问你修改完之后数列的lis是多少。 询问独立。

 

对于原数列, 我们将它离散化, 令dp1[i]为以i为结尾位置的最长上升子序列的长度, dp[2]为以i结尾的从后往前的最长下降子序列的长度。

原数列的lis显然为max(dp1[i]+dp2[i]-1)。

然后我们求出哪些位置是关键位置, 所谓关键位置, 就是说如果把这个位置的值改变, 那么lis的值也许就会减1。  求关键位置的方法看代码。

 

 然后对于每个询问, 令x[i]为位置, y[i]为修改后并离散化的值,我们令dp3[i]表示将x[i]位置修改为y[i]之后, 以x[i]结尾的最长上升子序列的长度, dp4[i]为最长下降的长度。

那么对于每次询问, 如果x[i]是关键节点, ans[i] = max(lis-1, dp3[i]+dp4[i]-1), 否则的话, ans[i] = max(lis, dp3[i]+dp4[i]-1)。

具体的可以看代码。

还有一点要注意的是数组不能开成4e5, 要开成8e5。

#include <iostream>
#include <vector>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <map>
#include <set>
#include <string>
#include <queue>
#include <stack>
#include <bitset>
using namespace std;
#define pb(x) push_back(x)
#define ll long long
#define mk(x, y) make_pair(x, y)
#define lson l, m, rt<<1
#define mem(a) memset(a, 0, sizeof(a))
#define rson m+1, r, rt<<1|1
#define mem1(a) memset(a, -1, sizeof(a))
#define mem2(a) memset(a, 0x3f, sizeof(a))
#define rep(i, n, a) for(int i = a; i<n; i++)
#define fi first
#define se second
typedef pair<int, int> pll;
const double PI = acos(-1.0);
const double eps = 1e-8;
const int mod = 1e9+7;
const int inf = 1061109567;
const int dir[][2] = { {-1, 0}, {1, 0}, {0, -1}, {0, 1} };
const int maxn = 8e5+5;
int sum[maxn<<2], num[maxn], dp1[maxn], dp2[maxn], dp3[maxn], dp4[maxn], a[maxn], b[maxn];
int x[maxn], y[maxn], ans[maxn];
vector <pll> v[maxn];
void update(int p, int val, int l, int r, int rt) {
    if(l == r) {
        sum[rt] = max(sum[rt], val);
        return ;
    }
    int m = l+r>>1;
    if(p<=m)
        update(p, val, lson);
    else
        update(p, val, rson);
    sum[rt] = max(sum[rt<<1],sum[rt<<1|1]);
}
int query(int L, int R, int l, int r, int rt) {
    if(L>R)
        return 0;
    if(L<=l&&R>=r) {
        return sum[rt];
    }
    int m = l+r>>1, ret = 0;
    if(L<=m)
        ret = query(L, R, lson);
    if(R>m)
        ret = max(ret, query(L, R, rson));
    return ret;
}
int main()
{
    int n, m, cnt = 0;
    cin>>n>>m;
    for(int i = 1; i<=n; i++) {
        scanf("%d", &a[i]);
        b[cnt++] = a[i];
    }
    for(int i = 0; i<m; i++) {
        scanf("%d%d", &x[i], &y[i]);
        b[cnt++] = y[i];
        v[x[i]].pb(mk(i, y[i]));
    }
    sort(b, b+cnt);
    cnt = unique(b, b+cnt)-b;
    for(int i = 1; i<=n; i++) {
        a[i] = lower_bound(b, b+cnt, a[i])-b+1;
    }
    for(int i = 1; i<=n; i++) {
        dp1[i] = query(1, a[i]-1, 1, cnt, 1)+1;
        for(int j = 0; j<v[i].size(); j++) {
            int tmp = v[i][j].fi;
            int tmpy = lower_bound(b, b+cnt, v[i][j].se)-b+1;
            dp3[tmp] = query(1, tmpy-1, 1, cnt, 1)+1;
        }
        update(a[i], dp1[i], 1, cnt, 1);
    }
    mem(sum);
    for(int i = n; i>=1; i--) {
        dp2[i] = query(a[i]+1, cnt, 1, cnt, 1)+1;
        for(int j = 0; j<v[i].size(); j++) {
            int tmp = v[i][j].fi;
            int tmpy = lower_bound(b, b+cnt, v[i][j].se)-b+1;
            dp4[tmp] = query(tmpy+1, cnt, 1, cnt, 1)+1;
        }
        update(a[i], dp2[i], 1, cnt, 1);
    }
    int maxx = 0;
    for(int i = 1; i<=n; i++) {
        maxx = max(dp1[i]+dp2[i]-1, maxx);      //求原数列lis
    }
    for(int i = 1; i<=n; i++) {
        if(dp1[i]+dp2[i]-1 == maxx) {
            num[dp1[i]]++;              //如果num[dp1[i]] == 1, 那么它就是关键节点
        }
    }
    for(int i = 0; i<m; i++) {
        int tmp = maxx;
        if(dp1[x[i]]+dp2[x[i]]-1 == maxx && num[dp1[x[i]]] == 1) {
            tmp--;
        }
        tmp = max(tmp, dp3[i]+dp4[i]-1);
        ans[i] = tmp;
    }
    for(int i = 0; i<m; i++) {
        printf("%d\n", ans[i]);
    }
    return 0;
}

 

posted on 2016-03-09 09:24  yohaha  阅读(271)  评论(0编辑  收藏  举报

导航