1. 程式人生 > >I - Colonial Mansions Gym - 101962I[二分+線段樹]

I - Colonial Mansions Gym - 101962I[二分+線段樹]

題意:給出一個有n個數字的數列,有兩種操作

  1. 1 x H 將x位置的數字改為H
  2. 2 x H 從x出發在每次數字相差不超過H的條件下可以向左右拓展多少個

思路:可以維護一個差分序列,這裡維護的是相鄰兩個數字的差值(為了條件2),然後通過線段樹去維護這個差值,當更新的時候需要更新兩個差值,i - 1和i,因為更改i位置的數字會影響它本身與後面的差值,同樣會影響他前面數字與它的差值,所以每次更新需要線段樹兩次單點更新,查詢向左右分別拓展了多少的時候可以二分,因為距離具有單調性,查詢某個區間的最大值(差分後為最大差值),如果這個最大值滿足條件再拓展區間即可。複雜度O( n

l o g n l o g n nlognlogn )。


a

c   c o d e : ac\ code:

#include <bits/stdc++.h>
using namespace std; typedef long long ll; #define met(a, b) memset(a, b, sizeof(a)) #define rep(i, a, b) for(int i = a; i <= b; i++) #define per(i, a, b) for(int i = a; i >= b; i--) const int maxn = 1e6 + 10; const int inf = 0x3f3f3f3f; #define int ll struct TreeNode { int l, r, MAX, MIN; } treeNode[maxn << 2]; int a[maxn], hh[maxn]; void push_up(int root) { treeNode[root].MAX = max(treeNode[root << 1].MAX, treeNode[root << 1 | 1].MAX); treeNode[root].MIN = min(treeNode[root << 1].MIN, treeNode[root << 1 | 1].MIN); } void buildTree(int root, int l, int r) { treeNode[root].l = l; treeNode[root].r = r; if(l == r) { treeNode[root].MAX = treeNode[root].MIN = hh[l]; return; } int mid = (l + r) >> 1; buildTree(root << 1, l, mid); buildTree(root << 1 | 1, mid + 1, r); push_up(root); } void upd(int root, int pos, int x) { if(treeNode[root].l == treeNode[root].r) { treeNode[root].MAX = treeNode[root].MIN = x; return; } int mid = (treeNode[root].l + treeNode[root].r) >> 1; if(pos <= mid) upd(root << 1, pos, x); else upd(root << 1 | 1, pos, x); push_up(root); } int MAX, MIN; void query(int root, int l, int r) { if(l > r) { MAX = 0; return; } if(treeNode[root].l == l && treeNode[root].r == r) { MAX = max(MAX, treeNode[root].MAX); MIN = min(MIN, treeNode[root].MIN); return; } int mid = (treeNode[root].l + treeNode[root].r) >> 1; if(r <= mid) query(root << 1, l, r); else if(l > mid) query(root << 1 | 1, l, r); else { query(root << 1, l, mid); query(root << 1 | 1, mid + 1, r); } } int divide(int l, int r, int flag, int x, int h) { int res = 0; while(l <= r) { int mid = (l + r) >> 1; MAX = -inf; MIN = inf; if(flag == 0) query(1, mid, x - 1); else query(1, x, mid - 1); if(MAX <= h) { if(flag == 0) { res = max(x - mid, res); r = mid - 1; } else { res = max(mid - x, res); l = mid + 1; } } else { if(flag == 0) { l = mid + 1; } else { r = mid - 1; } } } return res; } #undef int int main() { #define int ll int n, q; while(~scanf("%lld%lld", &n, &q)) { rep(i, 1, n) scanf("%lld", &a[i]); rep(i, 1, n) { hh[i] = abs(a[i] - a[i + 1]); } hh[n] = 0; buildTree(1, 1, n); int com, x, h; while(q--) { scanf("%lld%lld%lld", &com, &x, &h); if(com == 1) { a[x] = h; hh[x] = abs(a[x] - a[x + 1]); upd(1, x, hh[x]); if(x - 1 > 0) { hh[x - 1] = abs(a[x - 1] - a[x]); upd(1, x - 1, hh[x - 1]); } } else { int ans = 1; ans += divide(x, n, 1, x, h); ans += divide(1, x, 0, x, h); printf("%lld\n", ans); } } } return 0; }