[luogu P1438] 無聊的數列
[luogu P1438] 無聊的數列
題目背景
無聊的YYB總喜歡搞出一些正常人無法搞出的東西。有一天,無聊的YYB想出了一道無聊的題:無聊的數列。。。(K峰:這題不是傻X題嗎)
題目描述
維護一個數列{a[i]},支持兩種操作:
1、1 L R K D:給出一個長度等於R-L+1的等差數列,首項為K,公差為D,並將它對應加到a[L]~a[R]的每一個數上。即:令a[L]=a[L]+K,a[L+1]=a[L+1]+K+D,
a[L+2]=a[L+2]+K+2D……a[R]=a[R]+K+(R-L)D。
2、2 P:詢問序列的第P個數的值a[P]。
輸入輸出格式
輸入格式:
第一行兩個整數數n,m,表示數列長度和操作個數。
第二行n個整數,第i個數表示a[i](i=1,2,3…,n)。
接下來的m行,表示m個操作,有兩種形式:
1 L R K D
2 P 字母意義見描述(L≤R)。
輸出格式:
對於每個詢問,輸出答案,每個答案占一行。
輸入輸出樣例
輸入樣例#1:5 2
1 2 3 4 5
1 2 4 1 2
2 3
輸出樣例#1:6
說明
數據規模:
0≤n,m≤100000
|a[i]|,|K|,|D|≤200
Hint:
有沒有巧妙的做法?
純粹是為了刷zkw線段樹才看這題的。。(標簽打著zkw我也沒辦法)
zkw是一種很棒棒的線段樹,將冗長的代碼(還是zkw清真)壓得很短,還是非遞歸的,常數小,空間小,效率高!
但是。。。
這一題花了本蒟蒻兩個下午+一個晚上的時間(悲劇),可能是因為我實在太菜了吧,旁邊xtx一眼用bit秒掉了這題(%%%)。
好吧,我承認用了與sol裏面都不同的方法(因為我要練zkw啊!!!)
因為我太菜了,不會bit,不會lazy,所以只能打打zkw了。。
我是這樣想的——
由於區間修改時,直接上去用數據結構修改是一件很麻煩的事情,那怎麽辦?
設原數組為o[1..n],設a[1]=o[1],a[2]=o[2]-o[1]...(dalao們一定都看出來了,這是差分數組)
這樣,修改就變成了:
a[l]+=k,a[l+1..r]+=d,a[r+1]-=k+(r-l)*d
但是。。仍然需要區間修改。。。怎麽辦?再差分!
設b[1]=a[1],b[2]=a[2]-a[1]...
這樣,修改又變成了:
b[l]+=k,b[l+1]+=d,b[r]-=k+(r-l+1)*d,b[r+1]+=k+(r-l)*d(別看就幾個式子,當時的我意識模糊推了好久)
顯然,我們現在只需要單點修改了,是不是很高興!!!
然而,查詢怎麽辦?
推一推。。。
o[x]=a[1]+a[2]+...+a[x]=b[1]+b[1]+b[2]+b[1]+b[2]+b[3]+...+b[1]+b[2]+..+b[x]=x*b[1]+(x-1)*b[2]+...+1*b[x]
這怎麽辦?
o[x]=(x+1)*(b[1]+b[2]+..+b[x])-(1*b[1]+2*b[2]+..+x*b[x])
好像可以了。。。我們發現,我們還需要在維護一個w數組其中w[i]=i*b[i]。
然後,詢問操作就變成了區間修改,或者說更簡單的區間修改(前綴和)。。
code:
1 #include<bits/stdc++.h> 2 #define LL long long 3 #define id(x) (m+x-1) 4 using namespace std; 5 const int N=400005; 6 int n,m,Q; LL o[N],b[N],w[N]; 7 void B() { 8 for (int i=1; i<=n; i++) scanf("%lld",&o[i]); 9 for (m=1; m<=n+1; m<<=1) ; 10 } 11 void U(int x,LL v) { 12 for (b[id(x)]+=v,w[id(x)]+=v*x,(x+=m-1)>>=1; x; x>>=1) 13 b[x]=b[x<<1]+b[x<<1|1],w[x]=w[x<<1]+w[x<<1|1]; 14 } 15 LL A(int x) { 16 LL ret=o[x]; 17 for (int i=id(x)+1; i!=1; i>>=1) 18 if (i&1) ret+=b[i^1]*(x+1)-w[i^1]; 19 return ret; 20 } 21 int main() { 22 scanf("%d%d",&n,&Q),B(); 23 for (int i=1; i<=Q; i++) { 24 int c,l,r,k,d; scanf("%d",&c); 25 if (c&1) { 26 scanf("%d%d%d%d",&l,&r,&k,&d); 27 U(l,k),U(l+1,d-k); 28 U(r+1,(LL)(-k)-(LL)(r-l+1)*d),U(r+2,(LL)k+(LL)(r-l)*d); 29 } else scanf("%d",&k),printf("%lld\n",A(k)); 30 } 31 return 0; 32 }View Code
然後,終於tmA掉了。。qwq
垃圾zkw,毀我青春 zkwdalao這麽強,當然要%一%啦~~~
[luogu P1438] 無聊的數列