Codeforces #345 div1 D. Zip-line LIS dp

来源:互联网 发布:怎么连接台湾的网络 编辑:程序博客网 时间:2024/06/07 06:36

题目

题目链接:http://codeforces.com/contest/650/problem/D

题目来源:http://codeforces.com/contest/650

简要题意:求改变某位置后的LIS,每次改变相互独立。

题解

真没想到LIS能玩这么多的花样。

修改一个点后经过这个位置的LIS只要排序下询问然后扫两遍就行了。

比较难求的是改变了一个位置的值后不经过改变的位置的LIS,求出后两者最大值就是结果了。

一个结论就是后面那个值不是LIS_LEN就是LIS_LEN-1

更进一步就是如果当前位置在所有LIS中就是LIS_LEN-1否则就是LIS_LEN。

做法具体是去求当前结尾的最长LIS和当前开头的最长LIS。通过两者之和是否为LIS_LEN+1判断是否在LIS中,如果在LIS中的位置只能出现在某个固定位置则这个位置的值属于所有LIS,可以对以该位置结尾的LIS的长度记数看是否只出现一次。

代码

#include <iostream>#include <cstdio>#include <cmath>#include <algorithm>#include <cstring>#include <stack>#include <queue>#include <string>#include <vector>#include <set>#include <map>#define fi first#define se secondusing namespace std;typedef long long LL;typedef pair<int,int> PII;// headconst int N = 4e5+5;const int INF = 0x3f3f3f3f;struct Query {    int a, b, no, ans;};bool cmp(const Query &a, const Query &b) {    return a.a < b.a;}bool cmp2(const Query &a, const Query &b) {    return a.no < b.no;}Query q[N];int a[N];int lis[N], l[N], r[N];bool all[N];int cnt[N];int n, m;int getPos(int x) {    return lower_bound(lis, lis + n, x) - lis;}int main() {    scanf("%d%d", &n, &m);    for (int i = 0; i < n; i++) {        scanf("%d", a+i);    }    for (int i = 0; i < m; i++) {        scanf("%d%d", &q[i].a, &q[i].b);        q[i].a--;        q[i].no = i;    }    sort(q, q + m, cmp);    memset(lis, INF, sizeof lis);    int last = 0;    for (int i = 0; i < n; i++) {        while (last < m && q[last].a == i) {            q[last++].ans += getPos(q[last].b);        }        int pos = getPos(a[i]);        lis[pos] = a[i];        l[i] = pos + 1;    }    int lislen = lower_bound(lis, lis + n, INF) - lis;    memset(lis, INF, sizeof lis);    last = m-1;    for (int i = n-1; ~i; i--) {        while (last >= 0 && q[last].a == i) {            q[last--].ans += getPos(-q[last].b);        }        int pos = getPos(-a[i]);        lis[pos] = -a[i];        r[i] = pos + 1;    }    for (int i = 0; i < n; i++) {        if (l[i] + r[i] != lislen + 1) continue;        cnt[l[i]]++;    }    for (int i = 0; i < n; i++) {        if (l[i] + r[i] != lislen + 1) continue;        all[i] = (cnt[l[i]] == 1);    }    sort(q, q + m, cmp2);    for (int i = 0; i < m; i++) {        printf("%d\n", max(q[i].ans + 1, lislen - all[q[i].a]));    }    return 0;}
0 0
原创粉丝点击