HDU 6406 Taotao Picks Apples 【线段树 + 单调队列】

11 篇文章 0 订阅
2 篇文章 0 订阅

Taotao Picks Apples

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

 

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.

Source

2018 Multi-University Training Contest 8


题意:有一颗苹果树,树上又苹果,按从前往后的顺序给出苹果的高度

taotao 要捡苹果,但是他捡苹果一定要按升序捡(第 i 个捡的苹果一定要比第 i - 1 个高,并且遇到一个可捡的就捡,第一个必捡)

思路:先做出前缀和后缀,分别表示  [ 1 , i ]  和 [ i , n ] 区间的上升元素个数

前缀好做,后缀用个反向的单调队列就可以了

然后就是在更改了一个值之后要做查询时要找到后面第一个比当前数大的值,用线段树维护区间最大值的下标就可以了

线段树要做两个操作,一个是查询区间最大值的下标,一个是查询区间里第一个比某个值大的数的下标

#include<bits/stdc++.h>
using namespace std;
#define mem(a,x) memset(a,x,sizeof(a))
#define ll long long
const int maxn = 1e5 + 5;
int q[maxn],p[maxn],que[maxn],a[maxn];
int id;
struct node {
    int l,r;
    int maxid,val;
} tree[maxn * 4];

void push_up(int root) {
    if(tree[root << 1].val >= tree[(root << 1) | 1].val) {
        tree[root].val = tree[root << 1].val;
        tree[root].maxid = tree[root << 1].maxid;
    } else {
        tree[root].val = tree[(root << 1) | 1].val;
        tree[root].maxid = tree[(root << 1) | 1].maxid;
    }
}

void build_tree(int l,int r,int root) {
    tree[root].l = l;
    tree[root].r = r;
    if(l == r) {
        tree[root].val = 0; // 这里给一个初始值
        tree[root].maxid = 0;
        return ;
    }
    int mid = (l + r) >> 1;
    build_tree(l,mid,root << 1);
    build_tree(mid + 1,r,(root << 1) | 1);
    push_up(root); //向上更新值
}

void query_max(int l,int r,int root) { // 区间查询最大值下标
    if(l <= tree[root].l && r >= tree[root].r) {
        if(tree[root].val > a[id]) {
            id = tree[root].maxid;
        }
        return;
    }
    int mid = (tree[root].l + tree[root].r) >> 1;
    if(l <= mid){
        query_max(l,r,root << 1);
    }    
    if(r > mid){

        query_max(l,r,(root << 1) | 1);
    }
        
}

void query_first_max(int l,int r,int root,int v) { // 区间查询第一个大于的值
    if(tree[root].l == tree[root].r) {
        if(tree[root].val > v) {
            id = min(id,tree[root].l);
        }
        return;
    }
    int mid = (tree[root].l + tree[root].r) >> 1;
    if(tree[root].l >= l && tree[root].r <= r) {
        if(tree[root << 1].val > v) {
            query_first_max(l,r,root << 1,v);
        } else if(tree[(root << 1) | 1].val > v) {
            query_first_max(l,r,(root << 1) | 1,v);
        }
        return;
    }

    if(l <= mid)
        query_first_max(l,r,root << 1,v);
    if(r > mid)
        query_first_max(l,r,(root << 1) | 1,v);
}

void update(int p,int v,int root) { //单点更新
    if(tree[root].l == tree[root].r && tree[root].r == p) {
        tree[root].val = v;
        tree[root].maxid = p;
        return ;
    }
    int mid = (tree[root].l + tree[root].r) >> 1;
    if(p <= mid)
        update(p,v,root << 1);
    else
        update(p,v,(root << 1) | 1);
    push_up(root);  //每个点更新都要向上更新值
}

void init(int n) {
    build_tree(1,n,1);
    int head = 0,rear = 0;
    for(int i = n; i >= 1; i--) {
        while(rear > 0 && a[que[rear - 1]] <= a[i]) {
            rear--;
        }
        que[rear++] = i;
        p[i] = rear;
    }
    int maxx = -1,cnt = 0;
    for(int i = 1; i <= n; i++) {
        update(i,a[i],1);
        if(a[i] > maxx) {
            maxx = a[i];
            cnt++;
        }
        q[i] = cnt;
    }
}

int main() {
    int T,n,m,x,y;
    scanf("%d",&T);
    while(T--) {
        scanf("%d %d",&n,&m);
        for(int i = 1; i <= n; i++) {
            scanf("%d",&a[i]);
        }
        init(n);
        while(m--) {
            scanf("%d %d",&x,&y);
            int ans = 0;
            id = 0;
            if(x != 1){
                query_max(1,x - 1,1);
            }
            ans += q[id];
            if(y > a[id])
                ans++;
            else
                y = a[id];
            id = n + 1;
            if(x != n) {
                query_first_max(x + 1,n,1,y);
            }
            if(id <= n) {
                ans += p[id];
            }
            printf("%d\n",ans);
        }
    }
}
/**
10
11 5
1 7 2 3 8 9 5 6 7 10 11
6 7
2 2
11 12
10 13
1 9
*/

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值