BZOJ3922 Karin的弹幕

41 篇文章 0 订阅

考虑把询问的公差大的和小的分别考虑,大的直接暴力,对于小的公差,我们每个公差建一个1~N的线段树,维护1,1+i,1+2i...2,2+i,..3,3+i上的权值,这样一个等差序列就转换成一段区间,线段树上查就好了

讲道理这个算法取公差按根号分最优,复杂度是n sqrt n log n的……但是我们按5分,然后很快就过去了……

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<ctime>
#include<cmath>
#include<algorithm>
#include<iomanip>
#include<vector>
#include<map>
#include<set>
#include<bitset>
#include<queue>
#include<stack>
using namespace std;
#define MAXN 70010
#define MAXM 1010
#define INF 1000000000
#define MOD 1000000007
#define eps 1e-8
#define ll long long
int n,m;
int a[MAXN];
int p[6][MAXN],np[6][MAXN];
struct seg{
	int c;
	int v[MAXN<<2];
	inline void ud(int x){
		v[x]=max(v[x<<1],v[x<<1|1]);
	}
	void build(int x,int y,int z){
		if(y==z){
			v[x]=a[np[c][y]];
			return ;
		}
		int mid=y+z>>1;
		build(x<<1,y,mid);
		build(x<<1|1,mid+1,z);
		ud(x);
	}
	void change(int x,int y,int z,int p){
		if(y==z){
			v[x]=a[np[c][y]];
			return ;
		}
		int mid=y+z>>1;
		if(p<=mid){
			change(x<<1,y,mid,p);
		}else{
			change(x<<1|1,mid+1,z,p);
		}
		ud(x);
	}
	int ask(int x,int y,int z,int l,int r){
		if(y==l&&z==r){
			return v[x];
		}
		int mid=y+z>>1;
		if(r<=mid){
			return ask(x<<1,y,mid,l,r);
		}else if(l>mid){
			return ask(x<<1|1,mid+1,z,l,r);
		}else{
			return max(ask(x<<1,y,mid,l,mid),ask(x<<1|1,mid+1,z,mid+1,r));
		}
	}
};
seg T[6];
int main(){
	int i,j,o,x,y;
	scanf("%d",&n);
	for(i=1;i<=n;i++){
		scanf("%d",&a[i]);
	}
	for(i=1;i<=5;i++){
		int now=1;
		int st=1;
		for(j=1;j<=n;j++){
			p[i][now]=j;
			np[i][j]=now;
			now+=i;
			if(now>n){
				now=++st;
			}
		}
		T[i].c=i;
		T[i].build(1,1,n);
	}
	scanf("%d",&m);
	while(m--){
		scanf("%d%d%d",&o,&x,&y);
		if(o==0){
			a[x]+=y;
			for(i=1;i<=5;i++){
				T[i].change(1,1,n,p[i][x]);
			}
		}
		if(o==1){
			if(y<=5){
				int r=p[y][x]+(n-x)/y;
				printf("%d\n",T[y].ask(1,1,n,p[y][x],r));
			}else{
				int ans=a[x];
				for(i=x;i<=n;i+=y){
					ans=max(ans,a[i]);
				}
				printf("%d\n",ans);
			}
		}
	}
	return 0;
}

/*
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

*/


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值