题目背景

无聊的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:

有没有巧妙的做法?

线段树

只需要维护公差和首项即可。

坑坑坑,不能用读入优化

屠龙宝刀点击就送

#include <ctype.h>
#include <cstdio>
#define N 100005 int n,m;
struct Segment
{
int l,r,mid,val,flag,gc;
Segment *ch[];
Segment()
{
ch[]=ch[]=NULL;
gc=l=r=mid=val=flag=;
}
}*root=new Segment;
class segment
{
public:
void build(Segment *&k,int l,int r)
{
k=new Segment;
k->l=l;k->r=r;
if(l==r)
{
scanf("%d",&k->val);
return;
}
k->mid=l+r>>;
build(k->ch[],l,k->mid);
build(k->ch[],k->mid+,r);
}
void update(Segment *&k,int l,int r,int a,int b,int d)
{
if(k->l==l&&k->r==r)
{
k->flag+=a+b*(l-d);
k->gc+=b;
return;
}
if(l>k->mid) update(k->ch[],l,r,a,b,d);
else if(r<=k->mid) update(k->ch[],l,r,a,b,d);
else update(k->ch[],l,k->mid,a,b,d),update(k->ch[],k->mid+,r,a,b,d);
}
int query(Segment *&k,int x,int y)
{
if(k->l==k->r) return k->val+k->flag;
int ans;
if(x<=k->mid) ans=query(k->ch[],x,y);
else ans=query(k->ch[],x,y);
ans+=k->flag+k->gc*(y-k->l);
return ans;
}
};
class segment *tree;
int Main()
{
scanf("%d%d",&n,&m);
tree->build(root,,n);
for(int opt,a,b,c,d;m--;)
{
scanf("%d",&opt);
if(opt==)
{
scanf("%d%d%d%d",&a,&b,&c,&d);
tree->update(root,a,b,c,d,a);
}
else
{
scanf("%d",&a);
printf("%d\n",tree->query(root,a,a));
}
}
}
int sb=Main();
int main(int argc,char *argv[]) {;}
05-04 06:35