Codeforces 486E LIS of Sequence --树状数组求LIS
题意: 一个序列可能有多个最长子序列,现在问每个元素是以下三个种类的哪一类:
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类了。
代码:
#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; }
作者:whatbeg
出处1:http://whatbeg.com/
出处2:http://www.cnblogs.com/whatbeg/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
更多精彩文章抢先看?详见我的独立博客: whatbeg.com