所有增长最长的子序列的数量

时间:2014-04-07 21:39:45

标签: algorithm numbers dynamic-programming lis subsequence

我正在练习算法,我的任务之一是计算给定 0&lt;的所有最长增长子序列的。 n <= 10 ^ 6 个数。解决方案 O(n ^ 2)不是一个选项。

我已经实现了查找LIS及其长度(LIS Algorithm),但此算法将数字切换为尽可能低的数字。因此,我不可能确定具有先前数字(较大的数字)的子序列是否能够实现最长的长度,否则我可以计算这些开关。

有关如何在 O(nlogn)中获得此功能的任何想法?我知道应该使用动态编程解决它。

我实现了一个解决方案并且运行良好,但它需要两个嵌套循环(i in 1..n)x(j in 1..i-1)
  所以它是 O(n ^ 2)我认为,但它太慢了。

我甚至尝试将这些数字从数组移动到二叉树(因为在每个 i 迭代中,我查找所有较小的数字,然后 number [i] - 通过元素 i-1..1 ),但它甚至更慢。

示例测试:

1 3 2 2 4
result: 3 (1,3,4 | 1,2,4 | 1,2,4)

3 2 1
result: 3 (1 | 2 | 3)

16 5 8 6 1 10 5 2 15 3 2 4 1
result: 3 (5,8,10,15 | 5,6,10,15 | 1,2,3,4)

5 个答案:

答案 0 :(得分:20)

查找所有增长最长的子序列的数量

改进的LIS算法的完整Java代码,其不仅发现最长增长子序列的长度,而且发现这种长度的子序列的数量。我更喜欢使用泛型来不仅允许整数,而且允许任何类似的类型。

@Test
public void testLisNumberAndLength() {

    List<Integer> input = Arrays.asList(16, 5, 8, 6, 1, 10, 5, 2, 15, 3, 2, 4, 1);
    int[] result = lisNumberAndlength(input);
    System.out.println(String.format(
            "This sequence has %s longest increasing subsequenses of length %s", 
            result[0], result[1]
            ));
}


/**
 * Body of improved LIS algorithm
 */
public <T extends Comparable<T>> int[] lisNumberAndLength(List<T> input) {

    if (input.size() == 0) 
        return new int[] {0, 0};

    List<List<Sub<T>>> subs = new ArrayList<>();
    List<Sub<T>> tails = new ArrayList<>();

    for (T e : input) {
        int pos = search(tails, new Sub<>(e, 0), false);      // row for a new sub to be placed
        int sum = 1;
        if (pos > 0) {
            List<Sub<T>> pRow = subs.get(pos - 1);            // previous row
            int index = search(pRow, new Sub<T>(e, 0), true); // index of most left element that <= e
            if (pRow.get(index).value.compareTo(e) < 0) {
                index--;
            } 
            sum = pRow.get(pRow.size() - 1).sum;              // sum of tail element in previous row
            if (index >= 0) {
                sum -= pRow.get(index).sum;
            }
        }

        if (pos >= subs.size()) {                             // add a new row
            List<Sub<T>> row = new ArrayList<>();
            row.add(new Sub<>(e, sum));
            subs.add(row);
            tails.add(new Sub<>(e, 0));

        } else {                                              // add sub to existing row
            List<Sub<T>> row = subs.get(pos);
            Sub<T> tail = row.get(row.size() - 1); 
            if (tail.value.equals(e)) {
                tail.sum += sum;
            } else {
                row.add(new Sub<>(e, tail.sum + sum));
                tails.set(pos, new Sub<>(e, 0));
            }
        }
    }

    List<Sub<T>> lastRow = subs.get(subs.size() - 1);
    Sub<T> last = lastRow.get(lastRow.size() - 1);
    return new int[]{last.sum, subs.size()};
}



/**
 * Implementation of binary search in a sorted list
 */
public <T> int search(List<? extends Comparable<T>> a, T v, boolean reversed) {

    if (a.size() == 0)
        return 0;

    int sign = reversed ? -1 : 1;
    int right = a.size() - 1;

    Comparable<T> vRight = a.get(right);
    if (vRight.compareTo(v) * sign < 0)
        return right + 1;

    int left = 0;
    int pos = 0;
    Comparable<T> vPos;
    Comparable<T> vLeft = a.get(left);

    for(;;) {
        if (right - left <= 1) {
            if (vRight.compareTo(v) * sign >= 0 && vLeft.compareTo(v) * sign < 0) 
                return right;
            else 
                return left;
        }
        pos = (left + right) >>> 1;
        vPos = a.get(pos);
        if (vPos.equals(v)) {
            return pos;
        } else if (vPos.compareTo(v) * sign > 0) {
            right = pos;
            vRight = vPos;
        } else {
            left = pos;
            vLeft = vPos;
        }
    } 
}



/**
 * Class for 'sub' pairs
 */
public static class Sub<T extends Comparable<T>> implements Comparable<Sub<T>> {

    T value;
    int sum;

    public Sub(T value, int sum) { 
        this.value = value; 
        this.sum = sum; 
    }

    @Override public String toString() {
        return String.format("(%s, %s)", value, sum); 
    }

    @Override public int compareTo(Sub<T> another) { 
        return this.value.compareTo(another.value); 
    }
}

说明

由于我的解释似乎很长,我将调用初始序列&#34; seq&#34;及其任何子序列&#34; sub&#34;。因此,任务是计算可从seq。

获得的最长增长潜艇的数量

正如我之前提到的,想法是保留前面步骤中获得的所有可能最长的潜艇的计数。因此,让我们创建一个编号的行列表,其中每行的数量等于此行中存储的子的长度。并且让我们将数字存储为数字对(v,c),其中&#34; v&#34;是&#34;价值&#34;结束元素,&#34; c&#34; &#34; count&#34;给定长度的子节点以&#34; v&#34; 结束。例如:

1: (16, 1) // that means that so far we have 1 sub of length 1 which ends by 16.

我们将逐步构建这样的列表,按顺序从初始序列中获取元素。在每一步中,我们都会尝试将此元素添加到可以添加到并记录更改的最长子元素中。

建立清单

让我们使用您示例中的序列构建列表,因为它具有所有可能的选项:

 16 5 8 6 1 10 5 2 15 3 2 4 1

首先,取元素 16 。到目前为止,我们的列表是空的,所以我们只在其中放入一对:

1: (16, 1) <= one sub that ends by 16

接下来 5 。它不能添加到以16结尾的子中,因此它将创建长度为1的新子。我们创建一对(5,1)并将其放入第1行:

1: (16, 1)(5, 1)

元素 8 接下来。它不能创建长度为2的子[16,8],但可以创建子[5,8]。所以,这就是算法的来源。首先,我们颠倒列表行,查看&#34;值&#34;最后一对。如果我们的元素大于所有行中所有最后元素的值,那么我们可以将它添加到现有子元素,将其长度增加一。因此,值8将创建列表的新行,因为它大于目前列表中存在的所有最后元素的值(即,&gt; 5):

1: (16, 1)(5, 1) 
2: (8, ?)   <=== need to resolve how many longest subs ending by 8 can be obtained

元素8可以继续5,但不能继续16.所以我们需要搜索前一行,从结束开始,计算&#34;计数&#34;成对的&#34;价值&#34;小于8:

(16, 1)(5, 1)^  // sum = 0
(16, 1)^(5, 1)  // sum = 1
^(16, 1)(5, 1)  // value 16 >= 8: stop. count = sum = 1, so write 1 in pair next to 8

1: (16, 1)(5, 1)
2: (8, 1)  <=== so far we have 1 sub of length 2 which ends by 8.

为什么我们不将值8存储到长度为1(第一行)的子设备中?因为我们需要最大可能长度的子,并且8可以继续一些先前的子。因此,每个大于8的下一个数字也将继续这样的子数,并且不需要保持8作为长度的子数减去它。

下一步。的 6 即可。通过最后的&#34;值进行颠倒搜索&#34;在行中:

1: (16, 1)(5, 1)  <=== 5 < 6, go next
2: (8, 1)

1: (16, 1)(5, 1)
2: (8, 1 )  <=== 8 >= 6, so 6 should be put here
找到6个房间,需要计算一个计数:

take previous line
(16, 1)(5, 1)^  // sum = 0
(16, 1)^(5, 1)  // 5 < 6: sum = 1
^(16, 1)(5, 1)  // 16 >= 6: stop, write count = sum = 1

1: (16, 1)(5, 1)
2: (8, 1)(6, 1) 

处理 1 后:

1: (16, 1)(5, 1)(1, 1) <===
2: (8, 1)(6, 1)

处理 10 后:

1: (16, 1)(5, 1)(1, 1)
2: (8, 1)(6, 1)
3: (10, 2) <=== count is 2 because both "values" 8 and 6 from previous row are less than 10, so we summarized their "counts": 1 + 1

处理 5 后:

1: (16, 1)(5, 1)(1, 1)
2: (8, 1)(6, 1)(5, 1) <===
3: (10, 2)

处理 2 后:

1: (16, 1)(5, 1)(1, 1)
2: (8, 1)(6, 1)(5, 1)(2, 1) <===
3: (10, 2)

处理 15 后:

1: (16, 1)(5, 1)(1, 1)
2: (8, 1)(6, 1)(5, 1)(2, 1)
3: (10, 2)
4: (15, 2) <===

处理 3 后:

1: (16, 1)(5, 1)(1, 1)
2: (8, 1)(6, 1)(5, 1)(2, 1)
3: (10, 2)(3, 1) <===
4: (15, 2)  

处理 2 后:

1: (16, 1)(5, 1)(1, 1)
2: (8, 1)(6, 1)(5, 1)(2, 2) <===
3: (10, 2)(3, 1) 
4: (15, 2)  

如果在按最后一个元素搜索行时我们找到相等的元素,我们计算它的&#34; count&#34;再次基于前一行,并添加到现有&#34; count&#34;。

处理 4 后:

1: (16, 1)(5, 1)(1, 1)
2: (8, 1)(6, 1)(5, 1)(2, 2)  
3: (10, 2)(3, 1) 
4: (15, 2)(4, 1) <===

处理 1 后:

1: (16, 1)(5, 1)(1, 2) <===
2: (8, 1)(6, 1)(5, 1)(2, 2)  
3: (10, 2)(3, 1) 
4: (15, 2)(4, 1)  

那么在处理完所有初始序列后我们有什么?看最后一行,我们看到我们有3个最长的潜艇,每个潜艇由4个元件组成:2个结尾15个,1个结束4个。

复杂性怎么样?

在每次迭代中,当从初始序列中获取下一个元素时,我们进行2个循环:首先是迭代行以找到下一个元素的空间,第二个是汇总前一行中的计数。因此,对于每个元素,我们最大化为 n 迭代(最坏的情况:如果初始seq由按升序排列的元素组成,我们将得到n行的列表,每行有1对;如果seq已排序按降序排列,我们将获得包含n个元素的1行列表。顺便说一句, O(n 2 复杂性并不是我们想要的。

首先,显而易见的是,在每个中间状态行中,按照其最后一个&#34;值&#34;的递增顺序进行排序。因此,可以执行二进制搜索而不是暴力循环,其复杂度为O(log n)。

其次,我们不需要总结&#34;计数&#34;每次循环遍历行元素的subs。当新的对添加到行中时,我们可以在过程中对它们进行汇总,例如:

1: (16, 1)(5, 2) <=== instead of 1, put 1 + "count" of previous element in the row

因此,第二个数字将显示最终可以通过给定值获得的最长潜艇的计数,但所有最长潜艇的汇总计数任何大于或等于&#34;值&#34;的元素从这对。

因此,&#34;计数&#34;将被&#34; sums&#34;取代。而不是迭代上一行中的元素,我们只是执行二分搜索(这是可能的,因为任何行中的对总是按其&#34;值&#34;排序)并采取&#34; sum&#34;对于新对和&#34;总和&#34;前一行中的最后一个元素减去&#34;总和&#34;从元素左边到上一行中找到的位置再加上&#34;总和&#34;当前行中的前一个元素。

所以当处理 4 时:

1: (16, 1)(5, 2)(1, 3)
2: (8, 1)(6, 2)(5, 3)(2, 5) 
3: (10, 2)(3, 3) 
4: (15, 2) <=== room for (4, ?)

search in row 3 by "values" < 4:
3: (10, 2)^(3, 3) 

4将与(3-2 + 2)配对:(&#34;总和&#34;来自前一行的最后一对) - (&#34;总和&#34;从左对齐到找到的位置)前一行)+(&#34;总和&#34;来自当前行中的前一对):

4: (15, 2)(4, 3)

在这种情况下,所有最长潜艇的最终计数是&#34;总和&#34;从列表最后一行的最后一对开始,i。即3,而不是3 + 2。

因此,对行搜索和求和搜索执行二进制搜索,我们将带有O(n * log n)复杂度。

消耗的内存如何,在处理完所有数组之后我们获得最多n对,因此在动态数组的情况下,内存消耗将为O(n)。此外,在使用动态数组或集合时,需要一些额外的时间来分配和调整它们,但大多数操作都是在O(1)时间内完成的,因为我们在处理过程中不进行任何类型的排序和重新排列。所以复杂性估计似乎是最终的。

答案 1 :(得分:0)

Sasha Salauyou的答案很棒,但我不清楚为什么

sum -= pRow.get(index).sum;

这是基于相同想法的代码

import java.math.BigDecimal;
import java.util.*;

class lisCount {
  static BigDecimal lisCount(int[] a) {
    class Container {
      Integer    v;
      BigDecimal count;

      Container(Integer v) {
        this.v = v;
      }
    }
    List<List<Container>> lisIdxSeq = new ArrayList<List<Container>>();
    int lisLen, lastIdx;
    List<Container> lisSeqL;
    Container lisEle;
    BigDecimal count;
    int pre;
    for (int i = 0; i < a.length; i++){
      pre = -1;
      count = new BigDecimal(1);
      lisLen = lisIdxSeq.size();
      lastIdx = lisLen - 1;
      lisEle = new Container(i);
      if(lisLen == 0 || a[i] > a[lisIdxSeq.get(lastIdx).get(0).v]){
        // lis len increased
        lisSeqL = new ArrayList<Container>();
        lisSeqL.add(lisEle);
        lisIdxSeq.add(lisSeqL);
        pre = lastIdx;
      }else{
        int h = lastIdx;
        int l = 0;

        while(l < h){
          int m = (l + h) / 2;
          if(a[lisIdxSeq.get(m).get(0).v] < a[i]) l = m + 1;
          else h = m;
        }

        List<Container> lisSeqC = lisIdxSeq.get(l);
        if(a[i] <= a[lisSeqC.get(0).v]){
          int hi = lisSeqC.size() - 1;
          int lo = 0;
          while(hi < lo){
            int mi = (hi + lo) / 2;
            if(a[lisSeqC.get(mi).v] < a[i]) lo = mi + 1;
            else hi = mi;
          }
          lisSeqC.add(lo, lisEle);
          pre = l - 1;
        }
      }
      if(pre >= 0){
        Iterator<Container> it = lisIdxSeq.get(pre).iterator();
        count = new BigDecimal(0);
        while(it.hasNext()){
          Container nt = it.next();
          if(a[nt.v] < a[i]){
            count = count.add(nt.count);
          }else break;
        }
      }
      lisEle.count = count;
    }

    BigDecimal rst = new BigDecimal(0);
    Iterator<Container> i = lisIdxSeq.get(lisIdxSeq.size() - 1).iterator();
    while(i.hasNext()){
      rst = rst.add(i.next().count);
    }
    return rst;
  }

  public static void main(String[] args) {
    System.out.println(lisCount(new int[] { 1, 3, 2, 2, 4 }));
    System.out.println(lisCount(new int[] { 3, 2, 1 }));
    System.out.println(lisCount(new int[] { 16, 5, 8, 6, 1, 10, 5, 2, 15, 3, 2, 4, 1 }));
  }
}

答案 2 :(得分:0)

耐心排序也是O(N * logN),但比基于二分法搜索的方法更短更简单:

static int[] input = {4, 5, 2, 8, 9, 3, 6, 2, 7, 8, 6, 6, 7, 7, 3, 6};

/**
 * Every time a value is tested it either adds to the length of LIS (by calling decs.add() with it), or reduces the remaining smaller cards that must be found before LIS consists of smaller cards. This way all inputs/cards contribute in one way or another (except if they're equal to the biggest number in the sequence; if want't to include in sequence, replace 'card <= decs.get(decIndex)' with 'card < decs.get(decIndex)'. If they're bigger than all decs, they add to the length of LIS (which is something we want), while if they're smaller than a dec, they replace it. We want this, because the smaller the biggest dec is, the smaller input we need before we can add onto LIS.
 *
 * If we run into a decreasing sequence the input from this sequence will replace each other (because they'll always replace the leftmost dec). Thus this algorithm won't wrongfully register e.g. {2, 1, 3} as {2, 3}, but rather {2} -> {1} -> {1, 3}.
 *
 * WARNING: This can only be used to find length, not actual sequence, seeing how parts of the sequence will be replaced by smaller numbers trying to make their sequence dominate
 *
 * Due to bigger decs being added to the end/right of 'decs' and the leftmost decs always being the first to be replaced with smaller decs, the further a dec is to the right (the bigger it's index), the bigger it must be. Thus, by always replacing the leftmost decs, we don't run the risk of replacing the biggest number in a sequence (the number which determines if more cards can be added to that sequence) before a sequence with the same length but smaller numbers (thus currently equally good, due to length, and potentially better, due to less needed to increase length) has been found.
 */
static void patienceFindLISLength() {
    ArrayList<Integer> decs = new ArrayList<>();
    inputLoop: for (Integer card : input) {
        for (int decIndex = 0; decIndex < decs.size(); decIndex++) {
            if (card <= decs.get(decIndex)) {
                decs.set(decIndex, card);
                continue inputLoop;
            }
        }
        decs.add(card);
    }
    System.out.println(decs.size());
}

答案 3 :(得分:0)

上述逻辑的Cpp实现:

#include<bits/stdc++.h>
using namespace std;
#define pb push_back
#define pob pop_back
#define pll pair<ll, ll>
#define pii pair<int, int>
#define ll long long
#define ull unsigned long long
#define fori(a,b) for(i=a;i<b;i++)
#define forj(a,b) for(j=a;j<b;j++)
#define fork(a,b) for(k=a;k<b;k++)
#define forl(a,b) for(l=a;l<b;l++)
#define forir(a,b) for(i=a;i>=b;i--)
#define forjr(a,b) for(j=a;j>=b;j--)
#define mod 1000000007
#define boost std::ios::sync_with_stdio(false)

struct comp_pair_int_rev
{
    bool operator()(const pair<int,int> &a, const int & b)
    {
        return (a.first > b);
    }
    bool operator()(const int & a,const pair<int,int> &b)
    {
        return (a > b.first);
    }
};

struct comp_pair_int
{
    bool operator()(const pair<int,int> &a, const int & b)
    {
        return (a.first < b);
    }
    bool operator()(const int & a,const pair<int,int> &b)
    {
        return (a < b.first);
    }
};

int main()
{
    int n,i,mx=0,p,q,r,t;
    cin>>n;

    int a[n];
    vector<vector<pii > > v(100005);
    vector<pii > v1(100005);

    fori(0,n)
    cin>>a[i];

    v[1].pb({a[0], 1} );
    v1[1]= {a[0], 1};

    mx=1;
    fori(1,n)
    {
        if(a[i]<=v1[1].first)
        {
            r=v1[1].second;

            if(v1[1].first==a[i])
                v[1].pob();

            v1[1]= {a[i], r+1};
            v[1].pb({a[i], r+1});
        }
        else if(a[i]>v1[mx].first)
        {
            q=upper_bound(v[mx].begin(), v[mx].end(), a[i], comp_pair_int_rev() )-v[mx].begin();
            if(q==0)
            {
                r=v1[mx].second;
            }
            else
            {
                r=v1[mx].second-v[mx][q-1].second;
            }

            v1[++mx]= {a[i], r};
            v[mx].pb({a[i], r});
        }
        else if(a[i]==v1[mx].first)
        {
            q=upper_bound(v[mx-1].begin(), v[mx-1].end(), a[i], comp_pair_int_rev() )-v[mx-1].begin();
            if(q==0)
            {
                r=v1[mx-1].second;
            }
            else
            {
                r=v1[mx-1].second-v[mx-1][q-1].second;
            }
            p=v1[mx].second;
            v1[mx]= {a[i], p+r};

            v[mx].pob();
            v[mx].pb({a[i], p+r});


        }
        else
        {
            p=lower_bound(v1.begin()+1, v1.begin()+mx+1, a[i], comp_pair_int() )-v1.begin();
            t=v1[p].second;

            if(v1[p].first==a[i])
            {

                v[p].pob();
            }

            q=upper_bound(v[p-1].begin(), v[p-1].end(), a[i], comp_pair_int_rev() )-v[p-1].begin();
            if(q==0)
            {
                r=v1[p-1].second;
            }
            else
            {
                r=v1[p-1].second-v[p-1][q-1].second;
            }

            v1[p]= {a[i], t+r};
            v[p].pb({a[i], t+r});

        }


    }

    cout<<v1[mx].second;

    return 0;
}

答案 4 :(得分:0)

尽管我完全同意Alex的观点,但可以使用细分树轻松地完成此操作。 这是在NlogN中使用段树查找LIS长度的逻辑。 https://www.quora.com/What-is-the-approach-to-find-the-length-of-the-strictly-increasing-longest-subsequence 这是一种没有找到LIS但需要N ^ 2复杂度的方法。 https://codeforces.com/blog/entry/48677

我们使用段树(如here)来优化this中给出的方法。 这是逻辑:

首先以升序对数组进行排序(也保持原始顺序),用零初始化段树,段树应查询给定范围的两件事(为此使用对):        一种。第一的最大值。        b。秒的总和,对应于最大优先。 遍历排序数组。     令j为当前元素的原始索引,然后查询(0-j-1)并更新第j个元素(如果查询结果为0,0,则将其更新为(1,1))。

这是我在c ++中的代码:

#include<bits/stdc++.h>
#define tr(container, it) for(typeof(container.begin()) it = container.begin(); it != container.end(); it++)
#define ll          long long
#define pb          push_back
#define endl        '\n'
#define pii         pair<ll int,ll int>
#define vi          vector<ll int>
#define all(a)      (a).begin(),(a).end()
#define F           first
#define S           second
#define sz(x)       (ll int)x.size()
#define hell        1000000007
#define rep(i,a,b)  for(ll int i=a;i<b;i++)
#define lbnd        lower_bound
#define ubnd        upper_bound
#define bs          binary_search
#define mp          make_pair
using namespace std;

#define N  100005

ll max(ll a , ll b)

{
    if( a > b) return a ;
    else return
         b;
}
ll n,l,r;
vector< pii > seg(4*N);

pii query(ll cur,ll st,ll end,ll l,ll r)
{
    if(l<=st&&r>=end)
    return seg[cur];
    if(r<st||l>end)
    return mp(0,0);                           /*  2-change here  */
    ll mid=(st+end)>>1;
    pii ans1=query(2*cur,st,mid,l,r);
    pii ans2=query(2*cur+1,mid+1,end,l,r);
    if(ans1.F>ans2.F)
        return ans1;
    if(ans2.F>ans1.F)
        return ans2;

    return make_pair(ans1.F,ans2.S+ans1.S);                 /*  3-change here  */
}
void update(ll cur,ll st,ll end,ll pos,ll upd1, ll upd2)
{
    if(st==end)
    {
        // a[pos]=upd;                  /*  4-change here  */
        seg[cur].F=upd1;    
        seg[cur].S=upd2;            /*  5-change here  */
        return;
    }
    ll mid=(st+end)>>1;
    if(st<=pos&&pos<=mid)
        update(2*cur,st,mid,pos,upd1,upd2);
    else
        update(2*cur+1,mid+1,end,pos,upd1,upd2);
    seg[cur].F=max(seg[2*cur].F,seg[2*cur+1].F);


    if(seg[2*cur].F==seg[2*cur+1].F)
        seg[cur].S = seg[2*cur].S+seg[2*cur+1].S;
    else
    {
        if(seg[2*cur].F>seg[2*cur+1].F)
            seg[cur].S = seg[2*cur].S;
        else
            seg[cur].S = seg[2*cur+1].S;
        /*  6-change here  */
    }
}

int main()
{
    ios_base::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    int TESTS=1;
//  cin>>TESTS;
    while(TESTS--)
    {
        int n ;
        cin >> n;
        vector< pii > arr(n);
        rep(i,0,n)
        {
            cin >> arr[i].F;
            arr[i].S = -i;
        }

        sort(all(arr));
        update(1,0,n-1,-arr[0].S,1,1);
        rep(i,1,n)
        {
            pii x = query(1,0,n-1,-1,-arr[i].S - 1 );
            update(1,0,n-1,-arr[i].S,x.F+1,max(x.S,1));

        }

        cout<<seg[1].S;//answer



    }
    return 0;
}