BZOJ 3922:Karin的弹幕 【线段树】+【暴力】

| OI, CSDN

题意:

给定一个序列,支持以下操作:

  1. 对一段下标是等差数列的子序列进行求最大值操作(参见输入格式);
  2. 单点修改。

不知怎么回事,29号下午许多神犇好像在组队做这题。。于是ZMOIYNLP、Angelic47神犇邀请我这个蒟蒻一起做。。。。。 其实想法很简单,建许多线段树,不在线段树的情况暴力。线段树太多会MLE,太少时间效率我们认为不高(事实证明这是不准确的)。。。 于是我就把步长为100以下所有都建了线段树。。。。。发现T了。。。 然后我就乱搞,试图减小常数。。。但见效甚微 我们偶然的只把步长为4以下所有建了线段树。。。就飞快了。。。BZOJ上当前排第三。。 ZMOIYNLP的分块马上就要超过我啦!!!Angelic47的神奇算法也即将一飞冲天!!!


var
	a:array[0..70001]of longint;
	lch,rch,maxx:array[0..10000000]of longint;//事实上还是开大了
	ed,root:array[0..200,0..200]of longint;//ed[i,j]表示步长为i,从原序列中第j个开始的等差子序列的长度。root[i,j]表示步长为i,从原序列中第j个开始的等差子序列在线段树中的根
	n,m,i,x,y,tot,step,st,bound,rt,ans,op,up:longint;

function max(a,b:longint):longint;inline;
	begin
		if a>b then exit(a);exit(b);
	end;
	
procedure build(l,r,i:longint);
	var mid:longint;
	begin
		if l=r then begin maxx[i]:=a[st+(l-1)*step];exit;end;
		mid:=(l+r)>>1;
		inc(tot);
		lch[i]:=tot;
		build(l,mid,lch[i]);
		inc(tot);
		rch[i]:=tot;
		build(mid+1,r,rch[i]);
		//maxx[i]:=max(maxx[lch[i]],maxx[rch[i]]);
		if maxx[lch[i]]>maxx[rch[i]] then maxx[i]:=maxx[lch[i]] else maxx[i]:=maxx[rch[i]];
	end;

function get(s,t,l,r,i:longint):longint;
	var mid,a,b:longint;
	begin
		if (s<=l)and(t>=r) then exit(maxx[i]);
		mid:=(l+r)>>1;
		if s>mid then exit(get(s,t,mid+1,r,rch[i]));
		if t<=mid then exit(get(s,t,l,mid,lch[i]));
		//exit(max(get(s,t,l,mid,lch[i]),get(s,t,mid+1,r,rch[i])));
		a:=get(s,t,l,mid,lch[i]);
		b:=get(s,t,mid+1,r,rch[i]);
		if a>b then exit(a) else exit(b);
	end;

procedure update(p,l,r,i:longint);
	var mid:longint;
	begin
		if l=r then begin maxx[i]:=a[st+(p-1)*step];exit;end;
		mid:=(l+r)>>1;
		if p<=mid then update(p,l,mid,lch[i]) else update(p,mid+1,r,rch[i]);
		//maxx[i]:=max(maxx[lch[i]],maxx[rch[i]]);
		//我原来脑残的打了maxx[i]:=max(lch[i],rch[i]);结果蹦出来许多很大的数
		if maxx[lch[i]]>maxx[rch[i]] then maxx[i]:=maxx[lch[i]] else maxx[i]:=maxx[rch[i]];
	end;
	
begin
	up:=4;
	//assign(input,'in');reset(input);
	readln(n);
	if n<up then bound:=n else bound:=up;
	for i:=1 to n do read(a[i]);
	for step:=1 to bound do
		for st:=1 to step do
			begin
				inc(tot);
				root[step,st]:=tot;
				ed[step,st]:=(n-st)div step+1;
				build(1,ed[step,st],tot);
			end;
	//writeln(tot);
	readln(m);
	for m:=1 to m do
		begin
			readln(op,x,y);
			case op of
				1:
					begin
						if y>bound then//暴力
							begin
								//pos:=x;
								ans:=-maxlongint;
								while x<=n do
									begin
										if a[x]>ans then ans:=a[x];
										x:=x+y;
									end;
								writeln(ans);
								continue;
							end;
						st:=(x-1)mod y+1;
						rt:=root[y,st];
						ans:=get((x-st)div y+1,ed[y,st],1,ed[y,st],rt);
						writeln(ans);
					end;		
				0:
					begin
						inc(a[x],y);
						for step:=1 to bound do
							begin
								st:=(x-1)mod step+1;
								rt:=root[step,st];
								update((x-st)div step+1,1,ed[step,st],rt);
							end;
					end;
			end;
		end;
	close(input);close(output);
end.

【后记】好了,ZMOIYNLP已经第一啦!!!


原文地址