LIS的优化

二分优化

在求一个最长不上升自序列中,显然其结尾元素越小,越有利于接其他元素,对答案的贡献也就可能会更高

那么我们可以用low[i]去存长度为i的LIS结尾元素的最小值

因此我们只要维护low数组

对于每一个a[ i ],如果a[ i ] > low [当前最长的LIS长度],就把 a [ i ]接到当前最长的LIS后面,即low [++当前最长的LIS长度] = a [ i ]。

那么,怎么维护 low 数组呢?
对于每一个a [ i ],如果a [ i ]能接到 LIS 后面,就接上去;否则,就用 a [ i ] 取更新 low 数组。具体方法是,在low数组中找到第一个大于等于a [ i ]的元素low [ j ],用a [ i ]去更新 low [ j ]。如果从头到尾扫一遍 low 数组的话,时间复杂度仍是O(n^2)。我们注意到 low 数组内部一定是单调不降的,所有我们可以二分 low 数组,找出第一个大于a[ i ]的元素。二分一次 low 数组的时间复杂度的O(lgn),所以总的时间复杂度是O(nlogn)。

例题

P2782 友好城市

先将所有城市排序,然后发现就是一个最长不下降子序列

但暴力只能拿50pts

 1 /*
 2 Work by: Suzt_ilymics
 3 Knowledge: ??
 4 Time: O(??)
 5 */
 6 #include<iostream>
 7 #include<cstdio>
 8 #include<algorithm>
 9 using namespace std;
10 const int MAXN = 2e5+5;
11 struct good{
12     int n,s;
13     bool operator < (const good &b) const {return n == b.n ? s < b.s : n < b.n; }
14 }a[MAXN];
15 int n, ans;
16 int f[MAXN];
17 int main()
18 {
19     scanf("%d", &n);
20     for(int i = 1; i <= n; ++i){
21         scanf("%d%d", &a[i].n, &a[i].s);
22     }
23     
24     sort(a+1, a+n+1);
25     
26     for(int i = 1; i <= n; ++i){
27         f[i] = 1;
28         for(int j = 1; j < i; ++j){
29             if(a[j].n < a[i].n && a[j].s < a[i].s){
30                 f[i] = max(f[i], f[j] + 1);
31             }
32         }
33         ans = max(ans, f[i]);
34     }
35     
36     printf("%d", ans);
37     
38     return 0;
39 }

考虑一下上面的优化,因为北岸的城市是排好的,所以low数组里只需存南岸

 1 /*
 2 Work by: Suzt_ilymics
 3 Knowledge: LIS + 二分优化 
 4 Time: O(nlogn)
 5 */
 6 #include<iostream>
 7 #include<cstdio>
 8 #include<algorithm>
 9 #define INF 2100000000
10 using namespace std;
11 const int MAXN = 2e5+5;
12 struct good{
13     int n,s;
14     bool operator < (const good &b) const {return n == b.n ? s < b.s : n < b.n; }
15 }a[MAXN];
16 int n, ans;
17 int f[MAXN], low[MAXN];
18 
19 int ef(int r, int k){    
20     int mid, l = 0;
21     while(l <= r){
22         mid = (l + r) >> 1;
23         if(low[mid] <= k){
24             l = mid + 1;
25         }
26         else{
27             r = mid - 1;
28         }
29     }
30     return l;
31 }
32 
33 int main()
34 {
35     scanf("%d", &n);
36     for(int i = 1; i <= n; ++i){
37         scanf("%d%d", &a[i].n, &a[i].s);
38         low[i] = INF;
39     }
40     
41     sort(a+1, a+n+1);
42     
43     low[1] = a[1].s;
44     ans = 1;
45     
46     for(int i = 2; i <= n; ++i){
47         if(a[i].s > low[ans]){
48             low[++ans] = a[i].s;
49         }
50         else{
51             low[ ef(ans, a[i].s) ] = a[i].s;
52         }
53     }
54     
55     printf("%d", ans);
56     
57     return 0;
58 }
原文地址:https://www.cnblogs.com/Silymtics/p/13852302.html