1. 程式人生 > >[luogu P1438] 無聊的數列

[luogu P1438] 無聊的數列

sed ons das close logs src blog ide pen

[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] 無聊的數列