題目型別:差分,線段樹
傳送門:>here
<
所謂差分,我個人的理解就是用\(o(1)\)的方法來維護字首和,當然查詢變為了\(o(n)\)。差分就好像將字首和變成了乙個數一樣——當一段區間需要全部加上\(k\)時:差分陣列某一位上\(+k\),意味著這之後的所有元素都將\(+k\)。就好像一條帶子拖到最後了。因此我們如果僅僅操作乙個區間的話,那麼要把後面多出來的帶子減掉,於是我們再另外加一條負的帶子在後面。
剛才談論整個區間都加乙個相同的數。如果整個區間加的是乙個等差數列呢?相當於這個區間內所加的數,每個都比前面的多加\(d\)。效果就等價於在差分陣列中,令這個區間的每個元素加上\(d\)。然後末尾要減去末項。依然使用剛才的比喻,將那麼多條相同的帶子依次疊放,假設區間長度是\(l\),那麼最後乙個元素那裡肯定放著\(l\)條帶子了。而我們在最後需要把這\(l\)條帶子全部減掉。
因此,如果用差分來維護這道題,我們來總結一下步驟:(按照題意,等差數列的更新方法是\(l \ r \ k \ d\),代表左端點,右端點,首項,公差;設差分陣列為\(s\))
由此我們發現,對於大多數的情況都是\(+d\),因此轉化為乙個區間更新的問題。差分陣列的統計方法我們已經很熟悉了,需要從頭遍歷。因此元素\(p\)現在的值應該是:初始值 + \(s[1..p]\),因此轉化為乙個區間查詢的問題
因此我們可以用線段樹方便地\(o(logn)\)維護好
一直以為差分和線段樹維護的幾乎是同乙個東西,卻從來沒想過線段樹可以用來維護差分!線段樹維護差分,就好像求和的和。然而等差數列就好像是三維的一樣,先由差分轉化為二維,然後由線段樹轉化為線性。
正好像我們在找規律時所作的一樣,差,差之差,差之差之差。那麼這道題就好像倒過來,和,和的和,和的和的和……
不需要建樹,線段樹寫起來好像異常短小精悍……\(qwq\)
/*by dennyqi 2018*/
#include #include #include #include using namespace std;
typedef long long ll;
const int maxn = 100010;
const int inf = 1061109567;
inline int max(const int a, const int b)
inline int min(const int a, const int b)
inline int read()
int n,m,opt,l,r,x,y;
int a[maxn];
int val[maxn<<2],lazy[maxn<<2];
struct segmenttree
} int query(int rt, int l, int r, int x, int y)
void update(int rt, int l, int r, int x, int y, int k)
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()
while(m--)
else
} return 0;
}
洛谷 P1438 無聊的數列
題目背景 無聊的yyb總喜歡搞出一些正常人無法搞出的東西。有一天,無聊的yyb想出了一道無聊的題 無聊的數列。k峰 這題不是傻x題嗎 題目描述 維護乙個數列,支援兩種操作 1 1 l r k d 給出乙個長度等於r l 1的等差數列,首項為k,公差為d,並將它對應加到a l a r 的每乙個數上。即...
洛谷 P1438 無聊的數列
1 多次對於區間加上乙個等差數列,引數為l,r,k,d,表示首項為k,公差為d,將乙個長度r l 1的等差數列加到區間l.r上 2 詢問乙個值a i 要加上乙個等差數列,很容易想到差分,因此將題目簡化至下 1 將a l 加上k 2 將a l 1.r 加上d 3 將a r 1 r l d k 而查詢的...
洛谷 P1438 無聊的數列
p1438 無聊的數列 題目背景 無聊的yyb總喜歡搞出一些正常人無法搞出的東西。有一天,無聊的yyb想出了一道無聊的題 無聊的數列。k峰 這題不是傻x題嗎 題目描述 維護乙個數列,支援兩種操作 1 1 l r k d 給出乙個長度等於r l 1的等差數列,首項為k,公差為d,並將它對應加到a l ...