XTU1238 Segment Tree (線段樹·區間最值更新),xtu1238segment
題意 對一個數組有四種操作
- 1: 將區間[ l, r] 中的所有值都加上c
- 2:將區間 [l, r] 中所有比c大的值改為c
- 3:將區間 [l, r] 中所有比c小的值改為c
- 4:輸出區間 [l, r] 中所有數的最小值和最大值
對每個操作4輸出對應最小值和最大值
基礎的線段樹 在湘潭卡了好久沒寫出來
線段樹維護三個值 區間最大值 maxv, 區間最小值minv, 區間增加的值add
操作1是很容易實現的 操作2和3比1要複雜些 初一想要對每個值單獨進行操作 這樣肯定會T的 畢竟那樣用線段樹就沒意義了 後來發現每次更新時對應區間包含的所有最大區間節點的maxv 和 minv是可以確定的
- 操作2:maxv = min(maxv, c), minv = min(minv, c)
- 操作3 : maxv = max(maxv, c), minv = max(minv, c)
然後知道了父區間的maxv,minv後 通過pashdown函數就可以在需要時再對子區間進行更新 因為子區間的所有值都是在父區間的minv和maxv之間 然後就看代碼吧
#include <bits/stdc++.h>#define lc p<<1, s, mid#define rc p<<1|1, mid+1, e#define mid ((s+e)>>1)using namespace std;const int N = 200005;int maxv[N * 4], minv[N * 4], add[N * 4];void pushup(int p){ maxv[p] = max(maxv[p << 1], maxv[p << 1 | 1]); minv[p] = min(minv[p << 1], minv[p << 1 | 1]);}void pushdown(int p){ int l = p << 1; int r = p << 1 | 1; if(add[p]) { add[l] += add[p]; add[r] += add[p]; minv[l] += add[p]; minv[r] += add[p]; maxv[l] += add[p]; maxv[r] += add[p]; add[p] = 0; } //子區間的所有值肯定都父區間的minv~maxv之間 minv[l] = max(minv[l], minv[p]); minv[l] = min(minv[l], maxv[p]); maxv[l] = max(maxv[l], minv[p]); maxv[l] = min(maxv[l], maxv[p]); minv[r] = max(minv[r], minv[p]); minv[r] = min(minv[r], maxv[p]); maxv[r] = max(maxv[r], minv[p]); maxv[r] = min(maxv[r], maxv[p]);}void build(int p, int s, int e){ if(s == e) { scanf("%d", &maxv[p]); minv[p] = maxv[p]; return; } build(lc); build(rc); pushup(p);}void update(int p, int s, int e, int l, int r, int v, int op){ if(s >= l && e <= r) { if(op == 1) //將[l,r]區間的所有值都加上v { add[p] += v; minv[p] += v; maxv[p] += v; } else if (op == 2) //將[l,r]區間中所有大於v的值都改為v { maxv[p] = min(maxv[p], v); minv[p] = min(minv[p], v); } else //op = 3 將[l,r]區間中的所有小於v的值都改為v { maxv[p] = max(v, maxv[p]); minv[p] = max(v, minv[p]); } return; } pushdown(p); if(l <= mid) update(lc, l, r, v, op); if(r > mid) update(rc, l, r, v, op); pushup(p);}int query(int p, int s, int e, int l, int r, int op){ if(s == l && e == r)//op = 0 時查詢最小值 op = 1 時查詢最大值 return op ? maxv[p] : minv[p]; pushdown(p); if(r <= mid) return query(lc, l, r, op); if(l > mid) return query(rc, l, r, op); if(op) return max(query(lc, l, mid, op), query(rc, mid + 1, r, op)); return min(query(lc, l, mid, op), query(rc, mid + 1, r, op));}int main(){ int T, n, q, l, r, op, c, ax, in; scanf("%d", &T); while(T--) { memset(add, 0, sizeof(add)); scanf("%d%d", &n, &q); build(1, 1, n); while(q--) { scanf("%d%d%d", &op, &l, &r); if(op == 4) { ax = query(1, 1, n, l, r, 1); in = query(1, 1, n, l, r, 0); printf("%d %d\n", in, ax); } else { scanf("%d", &c); update(1, 1, n, l, r, c, op); } } } return 0;}
Segment Tree
Problem Description:
A contest is not integrity without problems about data structure.
There is an array a[1],a[2],…,a[n]. And q questions of the following 4 types: • 1 l r c - Update a[k] with a[k]+c for all l≤k≤r
• 2 l r c - Update a[k] with min{a[k],c} for all l≤k≤r;
• 3 l r c - Update a[k] with max{a[k],c} for all l≤k≤r;
• 4 l r - Ask for min{a[k]:l≤k≤r} and max{a[k]:l≤k≤r}.
Input
The first line contains a integer T(no more than 5) which represents the number of test cases.
For each test case, the first line contains 2 integers n,q (1≤n,q≤200000).
The second line contains n integers a1,a2,…,an which indicates the initial values of the array (|ai|≤).
Each of the following q lines contains an integer t which denotes the type of i-th question. If t=1,2,3, 3 integers l,r,c follows. If t=4, 2 integers l,r follows. (1≤ti≤4,1≤li≤ri≤n)
If t=1, |ci|≤2000;
If t=2,3, |ci|≤10^9.
Output
For each question of type 4, output two integers denote the minimum and the maximum.
Sample Input
1
1 1
1
4 1 1
Sample Output
1 1
Source
XTU OnlineJudge
著作權聲明:本文為博主原創文章,未經博主允許不得轉載。