洛谷P3130 haybalesCounting Haybale P 題解
阿新 • • 發佈:2021-08-20
題目
[USACO15DEC]haybalesCounting Haybale P
題解
最近剛剛自學了線段樹這個資料結構,恰巧做到了這道線段樹的模板題。其實也沒有什麼好多說的,接觸過線段樹的大犇肯定覺得很簡單。這道題注意的是修改區間的值時用到了lazy思想,如果只是用樸素的修改法則會超時。
果然,用樸素的方法更新值果然TLE了。
於是,我使用了lazy陣列,這樣可以儘可能地減少不必要的修改(如果有不理解的小夥伴可以上網搜尋線段樹lazy的含義與用法),最終終於AK了。
程式碼
這是TLE的程式碼(請勿學習)
#include<iostream> using namespace std; int n, m; typedef long long ll; #define MAX 200001 ll sum[MAX << 2]; int mm[MAX << 2]; int a[MAX]; char c; int le, ri, p; inline void pushup(int rt) { sum[rt] = sum[rt << 1] + sum[rt << 1 | 1]; mm[rt] = min(mm[rt << 1], mm[rt << 1 | 1]); } void build(int l, int r, int cur) { if (l == r) { sum[cur] = a[l]; mm[cur] = a[l]; return; } int mid = (l + r)>>1; build(l, mid, cur << 1); build(mid + 1, r, cur << 1 | 1); pushup(cur); } ll Sum(int L, int R, int l, int r, int cur) { if (l >= L && r <= R) return sum[cur]; int mid = (l + r) >> 1; ll res = 0; if (mid >= L) res += Sum(L, R, l, mid, cur << 1); if (mid < R) res += Sum(L, R, mid + 1, r, cur << 1 | 1); return res; } ll Min(int L, int R, int l, int r, int cur) { if (l>=L&&r<=R) return mm[cur]; int mid = (l + r) >> 1; if (mid >= R) return Min(L, R, l, mid, cur << 1); else if (mid < L) return Min(L, R, mid + 1, r, cur << 1 | 1); return min(Min(L, R, l, mid, cur << 1), Min(L, R, mid + 1, r, cur << 1 | 1)); } void update(int L, int R, int l, int r, int cur, int z) { if (l == r) { sum[cur] += z; mm[cur] += z; return; } int mid = (l + r) >> 1; if (mid >= L) update(L, R, l, mid, cur << 1, z); if (mid < R) update(L, R, mid + 1, r, cur << 1 | 1, z); pushup(cur); } int main() { ios::sync_with_stdio(false); cin >> n >> m; for (int i = 1; i <= n; i++) cin >> a[i]; build(1, n, 1); for (int i = 0; i < m; i++) { cin >> c; if (c == 'M') { cin >> le >> ri; cout << Min(le, ri, 1, n, 1) << '\n'; } else if (c == 'S') { cin >> le >> ri; cout<<Sum(le, ri, 1, n, 1)<<'\n'; } else { cin >> le >> ri >> p; update(le, ri, 1, n, 1, p); } } return 0; }
接下來是AC的(現學現碼)
#include<iostream> using namespace std; int n, m; typedef long long ll; #define MAX 200001 ll sum[MAX << 2]; int mm[MAX << 2]; ll lazy[MAX << 2]; int a[MAX]; char c; int le, ri, p; inline void pushup(int rt) { sum[rt] = sum[rt << 1] + sum[rt << 1 | 1]; mm[rt] = min(mm[rt << 1], mm[rt << 1 | 1]); } inline void pushdown(int rt, int l, int r) { lazy[rt << 1] += lazy[rt], lazy[rt << 1 | 1] += lazy[rt]; int mid = (l + r) / 2; sum[rt << 1] += lazy[rt] * (mid - l + 1); sum[rt << 1 | 1] += lazy[rt] * (r - mid); mm[rt << 1] += lazy[rt]; mm[rt << 1 | 1] += lazy[rt]; lazy[rt] = 0; } void build(int l, int r, int cur) { if (l == r) { sum[cur] = a[l]; mm[cur] = a[l]; return; } int mid = (l + r)>>1; build(l, mid, cur << 1); build(mid + 1, r, cur << 1 | 1); pushup(cur); } ll Sum(int L, int R, int l, int r, int cur) { if (l >= L && r <= R) return sum[cur]; if (lazy[cur]) pushdown(cur, l, r); int mid = (l + r) >> 1; ll res = 0; if (mid >= L) res += Sum(L, R, l, mid, cur << 1); if (mid < R) res += Sum(L, R, mid + 1, r, cur << 1 | 1); return res; } ll Min(int L, int R, int l, int r, int cur) { if (l>=L&&r<=R) return mm[cur]; if (lazy[cur]) pushdown(cur, l, r); int mid = (l + r) >> 1; if (mid >= R) return Min(L, R, l, mid, cur << 1); else if (mid < L) return Min(L, R, mid + 1, r, cur << 1 | 1); return min(Min(L, R, l, mid, cur << 1), Min(L, R, mid + 1, r, cur << 1 | 1)); } void update(int L, int R, int l, int r, int cur, int z) { if (l >= L&&r <= R) { sum[cur] += (ll)z * (r - l + 1); mm[cur] += z; lazy[cur] += z; return; } if (lazy[cur]) pushdown(cur, l, r); int mid = (l + r) >> 1; if (mid >= L) update(L, R, l, mid, cur << 1, z); if (mid < R) update(L, R, mid + 1, r, cur << 1 | 1, z); pushup(cur); } int main() { ios::sync_with_stdio(false); cin >> n >> m; for (int i = 1; i <= n; i++) cin >> a[i]; build(1, n, 1); for (int i = 0; i < m; i++) { cin >> c; if (c == 'M') { cin >> le >> ri; cout << Min(le, ri, 1, n, 1) << '\n'; } else if (c == 'S') { cin >> le >> ri; cout<<Sum(le, ri, 1, n, 1)<<'\n'; } else { cin >> le >> ri >> p; update(le, ri, 1, n, 1, p); } } return 0; }
感覺自己還是太菜了。