[DP] codeforces 650D. Zip-line

来源:互联网 发布:批发网络摄像头 编辑:程序博客网 时间:2024/06/08 00:21

题意:

给一个长度为n的序列ai,有m个询问,一次询问给出pos,val,问假如把apos变成val,序列的最长上升子序列的长度(设为lis)是多少,注意询问不会改变原序列。

题解:

a_{pos}apos变成val之后,通过思考可以发现单次询问时有两种情况,第一种是答案的lis中使用了val,第二种是没有使用。
首先考虑使用了,那么需要一些信息,lsa[i]表示以i为结尾的最长lis的长度,lsb[i]表示以i开头的最长lis的长度。
容易发现lsalsb都可以通过离线,在求原序列lis时求出来,正着求一次,倒着求一次就可以了,但是要注意询问里,i位置的lsa[i]lsb[i]可以多有多个值,每个都要对应保存下来。
当处理某个询问时,使用了val的答案就是lsa[i]+lsb[i]1
另外一种情况就是没有使用到val,就是判断apos在原序列的lis中是不是必须出现,如果可以被替代,那么答案就是lis,如果不可以被替代,答案是lis1
判断lis中哪些元素一定出现,就是这个题。
方法也是求出原序列的lsalsb,并且判断是否存在ijlsa[i]==lsa[j]lsa[i]+lsb[i]==lis1lsa[j]+lsb[j]==lis1
如果存在则说明ij可以互相替换。
这样两种情况就考虑完了。

#include<bits/stdc++.h>using namespace std;const int N = 4e5+5;const int inf = ~0u>>2;int a[N];struct Q{    int val, id;    Q(){}    Q(int b, int c){ val = b, id = c; }};vector<Q>qry[N];int lsa[N], lsb[N];int ansla[N], anslb[N];int ans[N];int p[N], pcnt;int n, m;int cs[N];bool ok[N];int main(){    scanf("%d%d", &n, &m);    for(int i = 1; i <= n; ++i) scanf("%d", a+i);    for(int i = 1; i <= m; ++i){        int pos, val;        scanf("%d%d", &pos, &val);        qry[pos].push_back(Q(val, i));    }    p[0] = -inf, pcnt = 1;    for(int i = 1; i <= n; ++i){        for(int k = qry[i].size()-1; k >= 0; --k){            int pos = lower_bound(p, p+pcnt, qry[i][k].val)-p;            ansla[qry[i][k].id] = pos;        }        int pos = lower_bound(p, p+pcnt, a[i])-p;        lsa[i] = pos;        p[pos] = a[i];        if(pos == pcnt) ++pcnt;    }    int lis = pcnt-1;    p[0] = -inf, pcnt = 1;    for(int i = n; i >= 1; --i){        for(int k = qry[i].size()-1; k >= 0; --k){            int pos = lower_bound(p, p+pcnt, -qry[i][k].val)-p;            anslb[qry[i][k].id] = pos;        }        int pos = lower_bound(p, p+pcnt, -a[i])-p;        lsb[i] = pos;        p[pos] = -a[i];        if(pos == pcnt) ++pcnt;    }    memset(cs, -1, sizeof(cs));    for(int i = 1; i <= n; ++i){        if(lsa[i] + lsb[i] == lis+1){            if(cs[lsa[i]] == -1) cs[lsa[i]] = i;            else cs[lsa[i]] = -2;        }    }    for(int i = 1; i <= lis; ++i) if(cs[i] > 0) ok[cs[i]] = 1;    for(int i = 1; i <= n; ++i){        for(int k = 0; k < qry[i].size(); ++k){            ans[qry[i][k].id] = max(ok[i]?lis-1:lis, ansla[qry[i][k].id]+anslb[qry[i][k].id]-1);        }    }    for(int i = 1; i <= m; ++i) printf("%d\n", ans[i]);}
0 0