P1438 无聊的数列题解
题目背景
无聊的 YYB 总喜欢搞出一些正常人无法搞出的东西。有一天,无聊的 YYB 想出了一道无聊的题:无聊的数列。。。
题目描述
维护一个数列 ai,支持两种操作:
-
1 l r K D:给出一个长度等于 r−l+1 的等差数列,首项为 K,公差为 D,并将它对应加到 [l,r] 范围中的每一个数上。即:令 al=al+K,al+1=al+1+K+D…ar=ar+K+(r−l)×D。 -
2 p:询问序列的第 p 个数的值 ap。
输入格式
第一行两个整数 n,m 表示数列长度和操作个数。
第二行 n 个整数,第 i 个数表示 ai。
接下来的 m 行,每行先输入一个整数 opt。
若 opt=1 则再输入四个整数 l r K D;
若 opt=2 则再输入一个整数 p。
输出格式
对于每个询问,一行一个整数表示答案。
输入输出样例
输入 #1复制
5 2 1 2 3 4 5 1 2 4 1 2 2 3
输出 #1复制
6
说明/提示
数据规模与约定
对于 100% 数据,0≤n,m≤105,−200≤ai,K,D≤200,1≤l≤r≤n,1≤p≤n。
思路
直接用线段树维护,细节见代码。
代码见下
#include<bits/stdc++.h>
using namespace std;
long long n,q,a[200005],aa,bb,cc,dd;
long long te[800005],te2[800005],siz[800005],lz[800005],lz2[800005];
char ch;
void ac(long long a1,long long k,long long d){
te[a1]+=k;
te2[a1]+=d;
lz[a1]+=k;
lz2[a1]+=d;
}
void down(long long a1){
ac(a1*2,lz[a1],lz2[a1]);
ac(a1*2+1,lz[a1]+lz2[a1]*siz[a1*2],lz2[a1]);
lz[a1]=0;
lz2[a1]=0;
}
void bu(long long a1,long long l,long long r){
siz[a1]=r-l+1;
if(l==r){
te[a1]=a[l];
te2[a1]=0;
lz[a1]=0;
lz2[a1]=0;
return ;
}
long long mid=(l+r)/2;
bu(a1*2,l,mid);
bu(a1*2+1,mid+1,r);
te[a1]=te[a1*2];
return ;
}
void ci(long long a1,long long l,long long r,long long x,long long y,long long k,long long d){
if(l>=x&&r<=y){
te[a1]+=k+d*(l-x);
te2[a1]+=d;
lz[a1]+=k+d*(l-x);
lz2[a1]+=d;
return ;
}
down(a1);
long long mid=(l+r)/2;
if(mid>=x){
ci(a1*2,l,mid,x,y,k,d);
}
if(mid+1<=y){
ci(a1*2+1,mid+1,r,x,y,k,d);
}
return ;
}
long long co(long long a1,long long l,long long r,long long x){
if(x==l&&l==r){
return te[a1];
}
down(a1);
long long mid=(l+r)/2;
if(mid>=x){
return co(a1*2,l,mid,x);
}
else{
return co(a1*2+1,mid+1,r,x);
}
}
int main(){
cin>>n>>q;
for(int i=1;i<=n;i++){
cin>>a[i];
}
bu(1,1,n);
for(int i=1;i<=q;i++){
cin>>ch;
if(ch=='2'){
cin>>aa;
cout<<co(1,1,n,aa)<<endl;
}
else{
cin>>aa>>bb>>cc>>dd;
ci(1,1,n,aa,bb,cc,dd);
}
}
return 0;
}

浙公网安备 33010602011771号