链接:
#include <stdio.h>
int main()
{
puts("转载请注明出处[vmurder]谢谢");
puts("网址:blog.csdn.net/vmurder/article/details/44978599");
}
题解:
我们对每个等差数列维护一棵线段树。
比如等差为 5 , n 为 17 ,则线段树内节点顺序为:
1,6,11,16,2,7,12,17,3,8,13,4,9,14,5,10,15。
然后查询的时候到对应线段树内查询一段就好了。
然后等差太大 (>5) 就不用维护线段树了,数量不会太多(虽然依然不少),直接暴力比较就行了。
实测:
下图由上至下分别维护到了: 8、7、3、4、6、5
代码:
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define N 300000
#define M 5
#define ls (note<<1)
#define rs (note<<1|1)
#define inf 0x3f3f3f3f
using namespace std;
int src[N],n,m;
struct Segment_Tree
{
int s[N],st[N],en[N],crs[N],t[N];
void pushup(int note)
{
s[note]=max(s[ls],s[rs]);
}
void build(int note=1,int l=1,int r=n)
{
if(l==r)
{
s[note]=t[l];
crs[l]=note;
return ;
}
int mid=l+r>>1;
build(ls,l,mid);
build(rs,mid+1,r);
pushup(note);
}
void init(int d)
{
int p=0;
for(int i=1;i<=d;i++)
{
for(int k=i;k<=n;k+=d)
{
st[k]=++p;
t[p]=src[k];
}
for(int k=i;k<=n;k+=d)en[k]=p;
}
build();
}
void add(int x,int w)
{
s[x=crs[st[x]]]+=w;
for(x>>=1;x;x>>=1)pushup(x);
}
int query(int l,int r,int note=1,int L=1,int R=n)
{
if(L==l&&r==R)return s[note];
int mid=L+R>>1;
if(r<=mid)return query(l,r,ls,L,mid);
else if(l>mid)return query(l,r,rs,mid+1,R);
else return max(query(l,mid,ls,L,mid),query(mid+1,r,rs,mid+1,R));
}
int ask(int x){return query(st[x],en[x]);}
}s[M+1];
int main()
{
// freopen("test.in","r",stdin);
int i,j,k;
scanf("%d",&n);
for(i=1;i<=n;i++)scanf("%d",&src[i]);
for(i=1;i<=M;i++)s[i].init(i);
for(scanf("%d",&m);m--;)
{
scanf("%d%d%d",&i,&j,&k);
if(i==0)
{
src[j]+=k;
for(i=1;i<=M;i++)s[i].add(j,k);
}
else {
if(k==0)printf("%d\n",src[j]);
else if(k>M)
{
int ans=-inf;
while(j<=n)ans=max(ans,src[j]),j+=k;
printf("%d\n",ans);
}
else printf("%d\n",s[k].ask(j));
}
}
return 0;
}
时间: 2024-12-13 01:53:34