6406】 Taotao Picks Apples 【單調佇列 + 線段樹(查詢區間第一個大於val的位置)】
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.
分析: 分為三部分求解, 修改位前面可以摘的個數,修改位是否用,修改位 後面可以摘的個數
程式碼
#include <map>
#include <set>
#include <queue>
#include <stack>
#include <list>
#include <string>
#include <math.h>
#include <time.h>
#include <stdio.h>
#include <string.h>
#include <vector>
#include <iostream>
#include <algorithm>
using namespace std;
#define rep(i, l, r) for(int i = l; i < r; i++)
#define per(i, r, l) for(int i = r; i >= l; i--)
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int>pii;
const int N = (int) 1e5 + 11;
const int M = (int) 1e6 + 11;
const int MOD = (int) 1e9 + 7;
const double EPS = (double) 1e-9;
const double PI = (double)acos(-1.0);
const int INF = (int) 0x3f3f3f3f;
const ll INFF = (ll) 0x3f3f3f3f3f3f3f3f;
void read(int &x){
char ch = getchar(); x = 0;
while(ch < '0' || ch > '9') ch = getchar();
while(ch >= '0' && ch <= '9') { x = x * 10 + ch - '0'; ch = getchar(); }
}
/*-----------------------------------------------------------------------------------*/
struct Q{ // 離線詢問
int pos, val, id;
Q(){}
Q(int _pos, int _val, int _id){
pos = _pos; val = _val; id = _id;
}
};
bool operator < (Q a, Q b){
return a.pos < b.pos;
}
int a[N], mx[N << 2];
void build(int rt, int L, int R){
if(L == R) {mx[rt] = a[L]; return ;}
int mid = (L + R) >> 1;
build(rt << 1, L, mid); build(rt << 1 | 1, mid + 1, R);
mx[rt] = max(mx[rt << 1], mx[rt << 1| 1]);
}
int query(int rt, int L, int R, int le, int ri, int val){ // [le, ri]中查詢第一個大於val的位置
if(L == R){
if(mx[rt] > val) return L;
else return -1;
}
if(le <= L && R <= ri) {
if(mx[rt] <= val) return -1;
}
int mid = (L + R) >> 1;
if(ri <= mid) return query(rt << 1, L, mid, le, ri, val);
if(le > mid) return query(rt << 1 | 1, mid + 1, R, le, ri, val);
int t = query(rt << 1, L, mid, le, mid, val);
if(t != -1) return t;
return query(rt << 1 | 1, mid + 1, R, mid + 1, ri, val);
}
int que[N], L, R; int suf[N], ans[N];
int main(){
#ifndef ONLINE_JUDGE
freopen("in.txt", "r", stdin);
freopen("out.txt", "w", stdout);
#endif
int _; scanf("%d", &_);
while(_--){
int n, m; read(n); read(m);
rep(i, 1, n + 1) read(a[i]);
build(1, 1, n);
L = 0, R = -1;
per(i, n, 1) {
while(L <= R && a[que[R]] <= a[i]) R--;
que[++R] = i;
suf[i] = (R - L + 1); // 單調佇列預處理出來 從i出發到最後可以摘的個數
}
vector<Q>ve; int pos, val;
rep(i, 1, m + 1){
read(pos); read(val);
ve.push_back(Q(pos, val, i));
}
sort(ve.begin(), ve.end());
int ma = 0, cc = 0, int clock = 0;
rep(i, 1, n + 1){
while(clock + 1 <= m && ve[clock].pos == i){
int tmp = ma;
int add = 0, cnt = 0; if(ve[clock].val > tmp) tmp = ve[clock].val, add = 1; // add 是否利用了當前數
if(i + 1 <= n){
pos = query(1, 1, n, i + 1, n, tmp);
cnt = suf[pos];
}
ans[ve[clock].id] = cc + add + cnt; // 前面摘的個數+當前的個數+後面的個數
clock++;
}
if(ma < a[i]) ma = a[i], cc++;
}
rep(i, 1, m + 1) printf("%d\n", ans[i]);
}
return 0;
}