洛谷 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:
有没有巧妙的做法?
线段树
只需要维护公差和首项即可。
坑坑坑,不能用读入优化
#include <ctype.h> #include <cstdio> #define N 100005 int n,m; struct Segment { int l,r,mid,val,flag,gc; Segment *ch[2]; Segment() { ch[0]=ch[1]=NULL; gc=l=r=mid=val=flag=0; } }*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>>1; build(k->ch[0],l,k->mid); build(k->ch[1],k->mid+1,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[1],l,r,a,b,d); else if(r<=k->mid) update(k->ch[0],l,r,a,b,d); else update(k->ch[0],l,k->mid,a,b,d),update(k->ch[1],k->mid+1,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[0],x,y); else ans=query(k->ch[1],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,1,n); for(int opt,a,b,c,d;m--;) { scanf("%d",&opt); if(opt==1) { 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[]) {;}
我们都在命运之湖上荡舟划桨,波浪起伏着而我们无法逃脱孤航。但是假使我们迷失了方向,波浪将指引我们穿越另一天的曙光。