HDU 6406 Taotao Picks Apples(贪心枚举+优化+小暴力)

Taotao Picks Apples

Time Limit: 2000/2000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others)
Total Submission(s): 338    Accepted Submission(s): 87


 

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 h1,h2,⋯,hn, 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 hp). 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≤105), denoting the number of apples and the number of queries. It is then followed by a single line of n integers h1,h2,⋯,hn (1≤hi≤109), 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≤109), as described in the problem statement.

 

 

Output

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

 

 

Sample Input

 

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

 

 

Sample Output

 

1 5 3

Hint

For the first query, the heights of the apples were 5, 2, 3, 4, 4, so Taotao would only pick the first apple. For the second query, the heights of the apples were 1, 2, 3, 4, 5, so Taotao would pick all these five apples. For the third query, the heights of the apples were 1, 3, 3, 4, 4, so Taotao would pick the first, the second and the fourth apples.

题意:给你一个包含n(n<=1e5)个数的序列。然后m(m<=1e5)次修改,每次修改一个点的值。

刚开始ma=-1,从a[1]开始,碰到一个比他大的就变为a[i],然后cnt++,问每次修改后原序列cnt为多少。(每次修改相互独立)。

思路:比赛的时候就想方设法暴力+优化。。。预处理未修改的序列的答案序列的数字以及位置和cnt,然后预处理每个节点i后交换多少次(单调队列滑动窗口倒着做),预处理每个数a[i]后面最接近它的答案序列中的数的位置。然后对于每次修改的下标i是否在原先的答案序列中进行讨论。(其中有一种情况是必须暴力的,但是如果数据随机的话完全可以过的。而且加了超神输入挂以后只需要156ms,不加是500+ms。)由于调试中暴力的部分想当然的二分,然后WA了4次,该长记性了。。。

代码:

#include
#define ll long long
using namespace std;

 namespace fastIO {
    #define BUF_SIZE 100000
    //fread -> read
    bool IOerror = 0;
    inline char nc() {
        static char buf[BUF_SIZE], *p1 = buf + BUF_SIZE, *pend = buf + BUF_SIZE;
        if(p1 == pend) {
            p1 = buf;
            pend = buf + fread(buf, 1, BUF_SIZE, stdin);
            if(pend == p1) {
                IOerror = 1;
                return -1;
            }
        }
        return *p1++;
    }
    inline bool blank(char ch) {
        return ch == ' ' || ch == '\n' || ch == '\r' || ch == '\t';
    }
    inline void read(int &x) {
        char ch;
        while(blank(ch = nc()));
        if(IOerror) return;
        for(x = ch - '0'; (ch = nc()) >= '0' && ch <= '9'; x = x * 10 + ch - '0');
    }
    #undef BUF_SIZE
};
using namespace fastIO;
//void read(int &x){scanf("%d",&x);}
const int maxn=100010;
int n,m,k;
int a[maxn],s[maxn],ss[maxn],f;
int c[maxn],r[maxn];
int ans,ct,cnt,tmp,flag;
int qq[maxn],he,ti;
int main()
{
    int T,cas=1;
    read(T);
    while(T--)
    {
        read(n);read(m);
        ans=0;   flag=1; f=0;
        for(int i=0;ima) {s[f]=i;ss[f++]=a[i];ma=a[i];}
        }
        a[n+1]=0;ss[f]=1000000009;
        int j=f-1;
        for(int i=n;i>=1;i--)
        {
            if(j>0&&i==s[j-1]) j--;
            if(s[j]>=i)r[i]=s[j];
            else r[i]=n+1;
        }
        for(int h=1,t=0,i=n;i;i--)
        {
            while(h<=t&&a[qq[t]]<=a[i])t--;
            qq[++t]=i;
            c[i]=t;
        }
        ans=f;
        while(m--)
        {
            int x,y,tmp;
            read(x);read(y);
            if(r[x]==x)
            {
                if(y0) ma=ss[k-1];
                    else ma=-1;
                    tmp=k;
                    if(y>ma) {tmp++;ma=y;}
                    int i;
                    for(i=s[k]+1;i<=n;i++) if(a[i]>ma) break;//这个地方必须暴力找!!!
                    tmp+=c[i];
                }
                else
                {
                int k=lower_bound(ss,ss+f,a[x])-ss;
                tmp=k+1;
                k=lower_bound(ss+k+1,ss+f,y+1)-ss;
                tmp+=(f-k);
                }
            }
            else
            {
                int xx=r[x];
                if(xx==n+1)
                {
                    if(y>ss[f-1]) tmp=ans+1;
                    else tmp=ans;
                }
                else {
                int k=lower_bound(ss,ss+f,a[xx])-ss;
                if(k>0&&y>ss[k-1]&&y

 

你可能感兴趣的:(ACM,细节处理,队列,模拟,贪心,思维)