Description
Karin在战斗之余的闲暇时光里喜欢上B站看鬼畜视频,尤其喜欢发弹幕。她这天对一个视频的弹幕产生了兴趣,她记录了每个时间点的弹幕数量,并且可能对一段呈等差数列的时间的弹幕数量求最大值;她还可能修改某个时间点的弹幕数量。
为了不在Yuuna面前暴露出她弱爆了的数学能力,保持她傲娇的属性,你需要帮助她。
精简题意:给定一个序列,支持以下操作:①对一段下标是等差数列的子序列进行求最大值操作(参见输入格式);②单点修改。
Input
第一行是一个整数n,
第二行是一个长度为n的整数序列a1…an,
第三行是一个整数m,
接下来m行,每行首先有一个整数op,
然后,若op=0,则之后有两个整数p,v,代表将a[p]的值加上v,
若op=1,则之后有两个整数x0,d,代表询问max{a[x0],a[x0+d],a[x0+2d],…,a[x0+kd]}(x0+kd<=n,x0+(k+1)d>n)。
数据中可能有多余空格。
Output
对每个op=1,单独输出一行,代表该等差子序列的最大值。
Sample Input
【输入样例1】
10
1 6 1 4 9 4 8 2 8 5
10
1 3 3
0 5 4
0 3 8
1 2 5
1 4 8
1 7 5
1 3 6
0 1 2
1 5 3
1 4 9
【输入样例2】
10
-9 -6 2 -10 -2 -6 10 6 -4 -2
10
1 2 3
1 6 3
0 7 8
0 4 -6
0 10 -5
1 10 4
0 3 -8
1 2 4
0 10 -5
1 1 2
Sample Output
【输出样例1】
8
8
4
8
9
13
4
【输出样例2】
6
-4
-7
-6
18
HINT
【数据范围】
1<=n<=70000,
1<=m<=70000,
保证任何时刻abs(a[i])(1<=i<=n)<=2147483647,
0<=op<=1,
1<=p<=n,
abs(v)<=2147483647
1<=x0<=n,
1<=d<=n,
保证涉及的所有数在C++的int内。
2015.4.2新加四组数据
块爷的测试题
建一大堆线段树
公差大暴力,公差小线段树
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<vector>
#include<algorithm>
#define MAXN 70010
#define GET (ch>='0'&&ch<='9')
#define lchild rt<<1,l,mid
#define rchild rt<<1|1,mid+1,r
#define ln rt<<1
#define rn rt<<1|1
#define MAXINT 0x7fffffff
using namespace std;
int n,m,size;
int a[MAXN];
void in(int &x)
{
char ch=getchar();x=0;int flag=1;
while (!GET) flag=ch=='-'?-1:1,ch=getchar();
while (GET) x=x*10+ch-'0',ch=getchar();x*=flag;
}
struct seg { int l,r,maxn; };
vector<seg> tree[70][70];
vector<int> b[70][70];
void push_up(int k,int x0,int rt)
{
tree[k][x0][rt].maxn=max(tree[k][x0][ln].maxn,tree[k][x0][rn].maxn);
}
void build(int k,int x0,int rt,int l,int r)
{
tree[k][x0][rt].l=l;tree[k][x0][rt].r=r;int mid=(l+r)>>1;
if (l==r) { tree[k][x0][rt].maxn=b[k][x0][l];return; }
build(k,x0,lchild);build(k,x0,rchild);push_up(k,x0,rt);
}
void modify(int k,int x0,int rt,int x,int delta)
{
int L=tree[k][x0][rt].l,R=tree[k][x0][rt].r,mid=(L+R)>>1;
if (L==R) { tree[k][x0][rt].maxn+=delta;return; }
if (x<=mid) modify(k,x0,ln,x,delta); else modify(k,x0,rn,x,delta);
push_up(k,x0,rt);
}
int query(int k,int x0,int rt,int l,int r)
{
int L=tree[k][x0][rt].l,R=tree[k][x0][rt].r,mid=(L+R)>>1;
if (l<=L&&r>=R) return tree[k][x0][rt].maxn;
if (r<=mid) return query(k,x0,ln,l,r);
else if (l>mid) return query(k,x0,rn,l,r);
else return max(query(k,x0,ln,l,mid),query(k,x0,rn,mid+1,r));
}
int main()
{
in(n);int opt,x0,d;
for (int i=1;i<=n;i++) in(a[i]);
in(m);
size=(int)sqrt((double)m/(log((double)n)/log(2.0)))/14;
if (!size) size=1;
for (int i=1;i<=size;i++)//公差
for (int j=1;j<=size;j++)//首项
{
b[i][j].push_back(0);
for (int k=j;k<=n;k+=i) b[i][j].push_back(a[k]);
tree[i][j].assign((b[i][j].size()-1)<<2|1,(seg){0,0,-MAXINT});
build(i,j,1,1,b[i][j].size()-1);
}
for (int i=1;i<=m;i++)
{
in(opt);in(x0);in(d);
if (!opt)
{
a[x0]+=d;
for (int j=1;j<=size;j++)
{
int a=(x0%j!=0)?x0%j:j;//计算首项
int pos=x0/j;
if (a!=j) ++pos;
modify(j,a,1,pos,d);
}
}
if (opt)
{
if (d>size)
{
int ans=-MAXINT;
for (int j=x0;j<=n;j+=d) ans=max(ans,a[j]);
printf("%d\n",ans);
}
else
{
int a=(x0%d!=0)?x0%d:d;
int pos=x0/d;
if (a!=d) ++pos;
int ans=query(d,a,1,pos,b[d][a].size()-1);
printf("%d\n",ans);
}
}
}
}