洛谷[P1438] 無聊的數列
阿新 • • 發佈:2018-10-06
def char 分數 都是 lse d+ ron 相同 線段 。效果就等價於在差分數組中,令這個區間的每個元素加上\(d\)。然後末尾要減去末項。依然使用剛才的比喻,將那麽多條相同的帶子依次疊放,假設區間長度是\(l\),那麽最後一個元素那裏肯定放著\(l\)條帶子了。而我們在最後需要把這\(l\)條帶子全部減掉。
現在的值應該是:初始值 + \(s[1..p]\),因此轉化為一個區間查詢的問題
題目類型:差分,線段樹
傳送門:>Here<
題意:給出一個數列,每次給一個區間對應的加上一個等差數列,並詢問某一個元素目前的值。
解題思路
所謂差分,我個人的理解就是用\(O(1)\)的方法來維護前綴和,當然查詢變為了\(O(n)\)。差分就好像將前綴和變成了一個數一樣——當一段區間需要全部加上\(k\)時:差分數組某一位上\(+k\),意味著這之後的所有元素都將\(+k\)。就好像一條帶子拖到最後了。因此我們如果僅僅操作一個區間的話,那麽要把後面多出來的帶子減掉,於是我們再另外加一條負的帶子在後面。
剛才談論整個區間都加一個相同的數。如果整個區間加的是一個等差數列呢?相當於這個區間內所加的數,每個都比前面的多加\(d\)
因此,如果用差分來維護這道題,我們來總結一下步驟:(按照題意,等差數列的更新方法是\(l \ r \ k \ d\),代表左端點,右端點,首項,公差;設差分數組為\(s\))
令\(s[l]+=k\)
令\(s[l+1..r]+=d\)
令\(s[r+1]-=k+d*(r-l)\)(末項)
由此我們發現,對於大多數的情況都是\(+d\),因此轉化為一個區間更新的問題。差分數組的統計方法我們已經很熟悉了,需要從頭遍歷。因此元素\(p\)
因此我們可以用線段樹方便地\(O(logn)\)維護好
反思
一直以為差分和線段樹維護的幾乎是同一個東西,卻從來沒想過線段樹可以用來維護差分!線段樹維護差分,就好像求和的和。然而等差數列就好像是三維的一樣,先由差分轉化為二維,然後由線段樹轉化為線性。
正好像我們在找規律時所作的一樣,差,差之差,差之差之差。那麽這道題就好像倒過來,和,和的和,和的和的和……
Code
不需要建樹,線段樹寫起來好像異常短小精悍……\(qwq\)
/*By DennyQi 2018*/ #include <cstdio> #include <queue> #include <cstring> #include <algorithm> using namespace std; typedef long long ll; const int MAXN = 100010; const int INF = 1061109567; inline int Max(const int a, const int b){ return (a > b) ? a : b; } inline int Min(const int a, const int b){ return (a < b) ? a : b; } inline int read(){ int x = 0; int w = 1; register char c = getchar(); for(; c ^ '-' && (c < '0' || c > '9'); c = getchar()); if(c == '-') w = -1, c = getchar(); for(; c >= '0' && c <= '9'; c = getchar()) x = (x<<3) + (x<<1) + c - '0'; return x * w; } int N,M,opt,l,r,x,y; int a[MAXN]; int val[MAXN<<2],lazy[MAXN<<2]; struct SegmentTree{ inline void pushdown(int rt, int l, int r){ if(lazy[rt]){ int mid = (l+r)/2; val[rt<<1] += lazy[rt] * (mid-l+1); val[rt<<1|1] += lazy[rt] * (r-(mid+1)+1); lazy[rt<<1] += lazy[rt]; lazy[rt<<1|1] += lazy[rt]; lazy[rt] = 0; } } int query(int rt, int l, int r, int x, int y){ if(l > y || r < x) return 0; if(x <= l && r <= y) return val[rt]; pushdown(rt, l, r); int mid = (l+r)/2; return query(rt<<1,l,mid,x,y) + query(rt<<1|1,mid+1,r,x,y); } void update(int rt, int l, int r, int x, int y, int k){ if(l > y || r < x) return; if(x <= l && r <= y){ lazy[rt] += k; val[rt] += (r-l+1) * k; return; } pushdown(rt,l,r); int mid = (l+r)/2; update(rt<<1,l,mid,x,y,k), update(rt<<1|1,mid+1,r,x,y,k); val[rt] = val[rt<<1] + val[rt<<1|1]; } }qxz; int main(){ N = read(), M = read(); for(int i = 1; i <= N; ++i){ a[i] = read(); } while(M--){ opt = read(); if(opt == 1){ l = read(), r = read(), x = read(), y = read(); qxz.update(1,1,N,l,l,x); qxz.update(1,1,N,l+1,r,y); qxz.update(1,1,N,r+1,r+1,-(x+y*(r-l))); } else{ x = read(); printf("%d\n", qxz.query(1,1,N,1,x)+a[x]); } } return 0; }
洛谷[P1438] 無聊的數列