1. 程式人生 > >無聊的數列

無聊的數列

規模 ons += earch r+ strong 實現 for 輸入輸出格式

題目背景

無聊的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

同樣的區間改值;

同樣的標記位置;

不用下傳!

由底向上;

遇到標記按規則變動;

tl存線段的左端點的位置,tk存線段的左端點的值,td存等差數列的公差;

代碼實現

 1 #include<cstdio>
 2 const int maxn=1<<19;
 3 int n,q,m;
 4 int a,b,c,d,e;
 5 int tl[maxn],tk[maxn],td[maxn];
 6 void build(){for(int i=m;i>0;i--) tl[i]=tl[i<<1
];} 7 void change(int L,int R,int k,int d){ 8 for(int l=L+m-1,r=R+m+1;l^r^1;l>>=1,r>>=1){ 9 if(l&1^1) tk[l^1]+=k+(tl[l^1]-L)*d,td[l^1]+=d; 10 if(r&1) tk[r^1]+=k+(tl[r^1]-L)*d,td[r^1]+=d; 11 } 12 } 13 int search(int p,int ret){ 14 for(int i=m+p;i>=1;i>>=1) ret+=tk[i]+(p-tl[i])*td[i]; 15 return ret; 16 } 17 int main(){ 18 scanf("%d%d",&n,&q); 19 for(m=1;m<=n;m<<=1); 20 for(int i=1;i<=n;i++) scanf("%d",&tk[m+i]),tl[m+i]=i; 21 build(); 22 while(q--){ 23 scanf("%d",&a); 24 if(a==1){ 25 scanf("%d%d%d%d",&b,&c,&d,&e); 26 change(b,c,d,e); 27 } 28 if(a==2){ 29 scanf("%d",&b); 30 printf("%d\n",search(b,0)); 31 } 32 } 33 return 0; 34 }

無聊的數列