【BZOJ3922】Karin的弹幕(均摊复杂度)(线段树)

传送门


题解:

对公差分块,小的直接建立线段树,大的暴力查。

但是由于两部分的常数差异,实际上公差阈值设成10就差不多了


代码:

#include<bits/stdc++.h>
#define ll long long
#define re register
#define gc get_char
#define cs const

namespace IO{
	inline char get_char(){
		static cs int Rlen=1<<22|1;
		static char buf[Rlen],*p1,*p2;
		return (p1==p2)&&(p2=(p1=buf)+fread(buf,1,Rlen,stdin),p1==p2)?EOF:*p1++;
	}
	
	template<typename T>
	inline T get(){
		char c;T num;bool f=false;
		while(!isdigit(c=gc()))f=c=='-';num=c^48;
		while(isdigit(c=gc()))num=(num+(num<<2)<<1)+(c^48);
		return f?-num:num;
	}
	inline int gi(){return get<int>();}
}
using namespace IO;

using std::cerr;
using std::cout;

cs int N=7e4+7,S=10,NINF=-0x3f3f3f3f;

int n,m;
int a[N],M;

struct data{
	int mx[N<<2];
	int st[N],ed[N],pos[N];
	
	void init(int d){
		int p=0;
		for(int re i=1;i<=d;++i){
			for(int re j=i;j<=n;j+=d)
			pos[st[j]=++p]=j;
			for(int re j=i;j<=n;j+=d)ed[j]=p;
		}
		build();
	}
	void build(){
		for(int re i=M+1;i<=M+n;++i)mx[i]=a[pos[i-M]];
		mx[M]=NINF;for(int re i=M+n+1;i<M+M;++i)mx[i]=NINF;
		for(int re i=M-1;i;--i)mx[i]=std::max(mx[i<<1],mx[i<<1|1]);
	}
	void modify(int p,int v){
		for(mx[p+=M]=v,p>>=1;p;p>>=1)mx[p]=std::max(mx[p<<1],mx[p<<1|1]); 
	}
	int query(int l,int r){
		int ans=NINF;
		for(l+=M-1,r+=M+1;l^r^1;l>>=1,r>>=1){
			if(l&1^1)ans=std::max(ans,mx[l^1]);
			if(r&1)  ans=std::max(ans,mx[r^1]);
		}
		return ans;
	}
	void update(int u,int v){modify(st[u],v);} 
	int query(int u){return query(st[u],ed[u]);}
}t[S+1];

signed main(){
#ifdef zxyoi
	freopen("karin.in","r",stdin);
#endif
	n=gi();
	for(M=1;M<=n+1;M<<=1);
	for(int re i=1;i<=n;++i)a[i]=gi();
	for(int re i=1;i<=S;++i)t[i].init(i);
	m=gi();
	while(m--){
		switch(gi()){
			case 0:{
				int p=gi(),v=gi();a[p]+=v;
				for(int re i=1;i<=S;++i)t[i].update(p,a[p]);
				break;
			}
			case 1:{
				int st=gi(),d=gi();
				if(d>S){
					int ans=NINF;
					for(;st<=n;st+=d)ans=std::max(ans,a[st]);
					cout<<ans<<"\n";
				}else cout<<t[d].query(st)<<"\n";
				break;
			}
		}
	}
	return 0;
} 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值