Codeforces 486E LIS of Sequence --树状数组求LIS

时间:2021-07-24 22:00:17

题意: 一个序列可能有多个最长子序列,现在问每个元素是以下三个种类的哪一类:

1.不属于任何一个最长子序列

2.属于其中某些但不是全部最长子序列

3.属于全部最长子序列

解法: 我们先求出dp1[i]表示1~i 的最长递增子序列长度, dp2[i]表示 n~i 的最长递减子序列长度(严格增减),这里我们可以用维护最大值的树状数组来解决,开始还以为要用nlogn求LIS的那种算法,当然那样应该也可以,这里元素值是1~10^5的,可以直接用树状数组,如果元素值任意的话,我们离散化一下也可以用树状数组。

求出dp1[],dp2[]后,我们先判断第1类: 当dp1[i] + dp2[i] != Length+1 (Length为LIS长度)的话,说明前后不一致,不属于最长子序列。

再判第3类,如果某个元素属于其中的一些最长子序列,那么他的dp1值一定不是唯一的,还有别的dp1值也等于他的dp1值,如1 2 3 5,那么dp1[2] = dp1[3] = 2.

所以先把第1类判掉以后,不考虑第1类,看dp1值是否重复来判第3类。第1,3类判完剩下的就是第2类了。

代码:

Codeforces 486E LIS of Sequence --树状数组求LISCodeforces 486E LIS of Sequence --树状数组求LIS
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <algorithm>
#include <string>
#include <vector>
#include <map>
#define lll __int64
using namespace std;
#define N 100107

int a[N],c[N],n,MAX;
int dp1[N],dp2[N];
string S;
int lowbit(int x) { return x&-x; }
void modify(int up,int x,int val) {
    if(up) {
        while(x <= MAX) {
            c[x] = max(c[x],val);
            x += lowbit(x);
        }
    }
    else {
        while(x > 0) {
            c[x] = max(c[x],val);
            x -= lowbit(x);
        }
    }
}
int getmax(int up,int x) {
    int maxi = 0;
    if(up) {
        while(x > 0) {
            maxi = max(maxi,c[x]);
            x -= lowbit(x);
        }
    }
    else {
        while(x <= MAX) {
            maxi = max(maxi,c[x]);
            x += lowbit(x);
        }
    }
    return maxi;
}
map<int,int> mp;

int main()
{
    int i,j;
    while(scanf("%d",&n)!=EOF)
    {
        S = "#"; MAX = 0;
        for(i=1;i<=n;i++) cin>>a[i], S += "0", MAX = max(MAX,a[i]);
        memset(c,0,sizeof(c));
        int LIS = 0;
        for(i=1;i<=n;i++) {
            int maxi = getmax(1,a[i]-1);
            dp1[i] = maxi+1;
            LIS = max(LIS,dp1[i]);
            modify(1,a[i],dp1[i]);
        }
        memset(c,0,sizeof(c));
        for(i=n;i>=1;i--) {
            int maxi = getmax(0,a[i]+1);
            dp2[i] = maxi+1;
            modify(0,a[i],dp2[i]);
        }
        mp.clear();
        for(i=1;i<=n;i++) {
            if(dp1[i] + dp2[i] - 1 != LIS) S[i] = '1';
            else mp[dp1[i]]++;
        }
        for(i=1;i<=n;i++)
            if(S[i] != '1' && mp[dp1[i]] == 1) S[i] = '3';
        for(i=1;i<=n;i++)
            if(S[i] == '0') S[i] = '2';
        cout<<S.substr(1,n)<<endl;
    }
    return 0;
}
View Code