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?
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.
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.Solution
拿到题最开始想用前缀和维护答案,但是没有理清思路,后来就乱了。看到一篇大神的线段树直接维护答案的题解,简单理了一下思路
对于线段树,维护区间最大值以及区间从左往右上升长度(即答案),我们注意到一个区间的答案=左区间答案数+右区间在左区间最大值基础上的贡献
对于一个查询query(rt,v)表示将区间t之前的一个数改为v后的区间rt的对答案的贡献,
若rt->maxx<v直接返回0,总的区间最大值小于v,这个区间不可能贡献答案
否则若rt->lson->maxx>v 此时只需关注左区间,因为右区间此时的贡献值和v不相关,注意这时的返回答案应该是tr[rt].cnt-tr[lson].cnt+query(lson,v),而不是tr[rson].cnt+query(lson,v)
这两者是不等价的,因为一个cnt表示的是当前区间从左到右的上升长度,而tr[rson].cnt仅仅关注的是右区间,没有和整体直接挂钩
再如果tr->lson->maxx<=v,此时左区间对答案无贡献,但右区间存在,查询右区间
大概就是这样,线段树维护答案很灵活感觉,唉本人垃圾是想不到了
贴一段大概理解之后写的ac代码吧
1 #include <bits/stdc++.h> 2 #define lson rt << 1 3 #define rson rt << 1 | 1 4 using namespace std; 5 using ll = long long; 6 using ull = unsigned long long; 7 using pa = pair<int, int>; 8 using ld = long double; 9 int n, m, k; 10 const int maxn = 1e5 + 10; 11 const int mod = 998244353; 12 int pre[maxn]; 13 template <class T> 14 inline T read(T &ret) 15 { 16 int f = 1; 17 ret = 0; 18 char ch = getchar(); 19 while (!isdigit(ch)) 20 { 21 if (ch == '-') 22 f = -1; 23 ch = getchar(); 24 } 25 while (isdigit(ch)) 26 { 27 ret = (ret << 1) + (ret << 3) + ch - '0'; 28 ch = getchar(); 29 } 30 ret *= f; 31 return ret; 32 } 33 template <class T> 34 inline void write(T n) 35 { 36 if (n < 0) 37 { 38 putchar('-'); 39 n = -n; 40 } 41 if (n >= 10) 42 { 43 write(n / 10); 44 } 45 putchar(n % 10 + '0'); 46 } 47 int a[maxn]; 48 struct node 49 { 50 int l, r, cnt, maxx; 51 } tr[maxn << 2]; 52 int query(int rt, int v) 53 { 54 int l = tr[rt].l; 55 int r = tr[rt].r; 56 if (l == r) 57 return tr[rt].maxx > v; 58 if (tr[rt].maxx < v) 59 return 0; 60 int mid = l + r >> 1; 61 if (tr[lson].maxx > v) //疑惑,为什么写出tr[rson].cnt+query(lson,v)答案不对 62 //啊左右区间和大区间并不相等,大区间=左区间+右区间贡献 63 return tr[rt].cnt - tr[lson].cnt + query(lson, v); 64 else 65 return query(rson, v); 66 } 67 void pushup(int rt) 68 { 69 tr[rt].maxx = max(tr[lson].maxx, tr[rson].maxx); 70 tr[rt].cnt = tr[lson].cnt + query(rson, tr[lson].maxx); 71 } 72 void build(int rt, int l, int r) 73 { 74 tr[rt].l = l; 75 tr[rt].r = r; 76 if (l == r) 77 { 78 tr[rt].cnt = 1; 79 tr[rt].maxx = a[l]; 80 return; 81 } 82 int mid = l + r >> 1; 83 build(lson, l, mid); 84 build(rson, mid + 1, r); 85 pushup(rt); 86 } 87 void update(int rt, int L, int v) 88 { 89 int l = tr[rt].l; 90 int r = tr[rt].r; 91 if (l == r && l == L) 92 { 93 tr[rt].maxx = v; 94 return; 95 } 96 int mid = l + r >> 1; 97 if (L <= mid) 98 update(lson, L, v); 99 else 100 update(rson, L, v); 101 pushup(rt); 102 } 103 int main(int argc, char const *argv[]) 104 { 105 ios::sync_with_stdio(false); 106 cin.tie(0); 107 cout.tie(0); 108 int t; 109 cin >> t; 110 while (t--) 111 { 112 cin >> n >> m; 113 for (int i = 1; i <= n; i++) 114 cin >> a[i]; 115 build(1, 1, n); 116 while (m--) 117 { 118 int p, q; 119 cin >> p >> q; 120 update(1, p, q); 121 cout << tr[1].cnt << " "; 122 update(1, p, a[p]); 123 } 124 } 125 return 0; 126 }