2018 Multi-University Training Contest 8&&HDU6406 Taotao Picks Apples【ST表&&LIS】

Taotao Picks Apples

Time Limit: 2000/2000 MS (Java/Others) Memory Limit: 131072/131072 K (Java/Others)

Problem Description

There is an apple tree in front of Taotao’s house. When autumn comes, n apples on the tree ripen, and Taotao will go to pick these apples.

When Taotao picks apples, Taotao scans these apples from the first one to the last one. If the current apple is the first apple, or it is strictly higher than the previously picked one, then Taotao will pick this apple; otherwise, he will not pick.

Given the heights of these apples h 1 , h 2 , , h n , you are required to answer some independent queries. Each query is two integers p,q, which asks the number of apples Taotao would pick, if the height of the p-th apple were q (instead of h p ). Can you answer all these queries?

Input

The first line of input is a single line of integer T ( 1 T 10 ) , the number of test cases.
Each test case begins with a line of two integers n , m ( 1 n , m 10 5 ) , denoting the number of apples and the number of queries. It is then followed by a single line of n integers h 1 , h 2 , , h n ( 1 h i 10 9 ) , denoting the heights of the apples. The next m lines give the queries. Each of these m lines contains two integers p ( 1 p n ) and q ( 1 q 10 9 ) , as described in the problem statement.

Output

For each query, display the answer in a single line.

Examples

Input
1
5 3
1 2 3 4 4
1 5
5 5
2 3

Output
1
5
3


【题目链接】 Taotao Picks Apples

【题意】
给一个序列,每次贪心选取比前一个数大的数,即最早的上升子序列。每次询问修改一个数,求修改后的序列的能选出 多少个数。询问不叠加。

【思路】

考虑每次修改不叠加,因此我们可以从如何对原序列进行预处理着手。
通过观察可以发现,将原序列从任意位置断开,我们可以通过分别维护左右段的某些信息来拼接 得到答案。
我们可以首先预处理出num数组,lis数组,Max数组,分别表示区间[i,n]的最早上升子序列长度,区间[1,i]的最早上升子序列长度,区间[1,i]的最大值

然后我们对于修改: x y 分成两种情况
当y>Max[x-1]时,说明这个位置对答案有贡献,那么我们先得到[1,x-1]的最早上升子序列长度,加1,然后再找到x位置右边第一个比y大的位置j,加上[j,n]的最早上升子序列长度即可。
当y<=Max[x-1]时,说明这个位置对答案没有贡献,那么我们先得到[1,x-1]的最早上升子序列长度,然后直接找到x位置右边第一个比Max[x-1]大的位置j,加上[j,n]的最早上升子序列长度即可。

为了优化查找的时间复杂度,我们先用ST表预处理出区间最大值,然后二分查找即可。

时间复杂度: n l o g n

#include <cstdio>
#include <bits/stdc++.h>
#include <map>
#include <cstring>
#include <algorithm>
using namespace std;
#define mst(a,b) memset((a),(b),sizeof(a))
#define rush() int T;scanf("%d",&T);while(T--)

typedef long long ll;
const int maxn = 100005;
const ll INF = 1e18;
const double eps = 1e-9;

int n,m;
int a[maxn];
char s[maxn];
int dp[maxn][20];
int num[maxn];
int lis[maxn];
int nex[maxn];
int Max[maxn];


void ST(int len)
{
    for(int i=1; i<=len; i++) dp[i][0]=a[i];
    int up=0;
    while((1<<up)<=len) up++;
    up--;
    for(int j=1; j<=up; j++)
    for(int i=1; i+(1<<j)-1<=len; i++)
    {
        dp[i][j]=max(dp[i][j-1],dp[i+(1<<(j-1))][j-1]);
    }
}

int query(int l,int r)
{
    int len=r-l+1;
    int up=0;
    while((1<<up)<=len) up++;
    up--;
    return max(dp[l][up],dp[r-(1<<up)+1][up]);
}


int find_pos(int x,int pos)
{
    int l=pos+1,r=n;
    int ans=-1;
    while(l<=r)
    {
        int mid=(l+r)/2;
        if(query(pos+1,mid)>x)
        {
            ans=mid;
            r=mid-1;
        }
        else l=mid+1;
    }
    return ans;
}

int main()
{
    rush()
    {
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++) scanf("%d",&a[i]);
        ST(n);
        nex[n]=n+1;
        num[n+1]=0;
        num[n]=1;
        for(int i=n-1;i>=1;i--)
        {
            int now=i+1;
            while(now<=n&&a[i]>=a[now]) now=nex[now];
            num[i]=num[now]+1;
            nex[i]=now;
        }
        lis[0]=0;
        lis[1]=1;
        Max[1]=a[1];
        for(int i=2;i<=n;i++)
        {
            Max[i]=max(Max[i-1],a[i]);
            if(Max[i]>Max[i-1]) lis[i]=lis[i-1]+1;
            else lis[i]=lis[i-1];
        }
        while(m--)
        {
            int x,y;
            scanf("%d%d",&x,&y);
            if(y>Max[x-1])
            {
                int pos=find_pos(y,x);
                if(pos==-1) printf("%d\n",lis[x-1]+1);
                else printf("%d\n",lis[x-1]+1+num[pos]);
            }
            else
            {
                int pos=find_pos(Max[x-1],x);
                if(pos==-1) printf("%d\n",lis[x-1]);
                else printf("%d\n",lis[x-1]+num[pos]);
            }
        }
    }
}
发布了259 篇原创文章 · 获赞 100 · 访问量 13万+

猜你喜欢

转载自blog.csdn.net/my_sunshine26/article/details/81743798
今日推荐