模拟赛11-28
https://www.luogu.org/contestnew/show/4300
第一题。。
第一眼数学题,第二眼lca,看了下数据范围,很明显连建边都建不了啊。。
在想了想,对于每个月,新生的兔子是斐波那契数列的第f[i]+1-f[i+1]项,而分别对应1-。。
想到这里正解就出来了,对于每个兔子,其父亲为x-最大的小于其的斐波那契数
而要查询lca,则只需一只兔子暴力往上(查找父节点时二分),记录一路以来的节点
对于另一只兔子,也只需往上跳,每到一个节点,二分查找一下前面那只兔子有没有到过
时间复杂度(m*树的高度*log(树的高度)) 显然树的高度不会太高,所以平摊下来的时间还是理想的
代码:
const maxn=1000000000000; var i,j:longint; n,m,c,d,ll,l,ans:int64; f,tmp:array[1..100]of int64; flag:boolean; function find1(x:int64):longint; var h,t,mid:longint; begin h:=1; t:=l; while h<t do begin mid:=(h+t) div 2; if f[mid]>=x then t:=mid else h:=mid+1; end; if f[h]>=x then dec(h); exit(h); end; function find2(x:int64):boolean; var h,t,mid:longint; begin h:=1; t:=ll+1; while h<t do begin mid:=(h+t) div 2; if tmp[mid]=x then exit(true); if tmp[mid]<x then t:=mid else h:=mid+1; end; exit(false); end; begin f[1]:=1; f[2]:=1; for i:=3 to 100 do begin f[i]:=f[i-1]+f[i-2]; if f[i]>maxn then break; end; l:=i; readln(n); for i:=1 to n do begin read(c,d); ll:=0; ans:=1; flag:=false; while c<>1 do begin inc(ll); tmp[ll]:=c; j:=find1(c); c:=c-f[j]; end; while d<>1 do begin if find2(d) then begin ans:=d; break; end; j:=find1(d); d:=d-f[j]; end; writeln(ans); end; end.
第二题。。
刚学完主席树不久。。。很明显的裸的主席树
显然,主席树第一维维护区间,第二维维护各种颜色的个数
注意到每次修改,实际上只有d1位置上各种颜色的兔子发生了变化,所以只需对d1处进行单点修改
代码:
uses math; type re=record h,t,x:longint; end; var p:array[0..20000000]of re; a,f:array[0..500000]of longint; n,m,i,j,tmp,c1,d1,e1,f1,ll:longint; procedure build(x,h,t:longint); var mid:longint; begin ll:=max(ll,x); p[x].h:=h; p[x].t:=t; if h=t then exit; mid:=(h+t) div 2; build(x*2,h,mid); build(x*2+1,mid+1,t); end; procedure insert(pre,x,h,t,sum:longint); var mid,tmp:longint; begin inc(ll); p[ll]:=p[pre]; inc(p[ll].x,sum); tmp:=ll; if h=t then exit; mid:=(h+t) div 2; if (x<=mid) then begin insert(p[ll].h,x,h,mid,sum); p[tmp].h:=tmp+1; end else begin insert(p[ll].t,x,mid+1,t,sum); p[tmp].t:=tmp+1; end; end; function query(x,y,z,h,t:longint):longint; var tmp,mid:longint; begin if h=t then exit(p[y].x-p[x].x); mid:=(h+t) div 2; if z<=mid then exit(query(p[x].h,p[y].h,z,h,mid)) else exit(query(p[x].t,p[y].t,z,mid+1,t)); end; begin readln(n,m); for i:=1 to n do read(a[i]); ll:=0; build(1,1,n); f[0]:=1; for i:=1 to n do begin f[i]:=ll+1; insert(f[i-1],a[i],1,n,1); end; for i:=1 to m do begin read(c1,d1); if c1=1 then begin read(e1,f1); writeln(query(f[d1-1],f[e1],f1,1,n)); end else begin tmp:=ll; insert(f[d1],a[d1],1,n,-1); f[d1]:=tmp+1; tmp:=ll; insert(f[d1],a[d1+1],1,n,1); f[d1]:=tmp+1; tmp:=ll; tmp:=a[d1]; a[d1]:=a[d1+1]; a[d1+1]:=tmp; end; end; end.
还是讲讲正解,vector+二分维护
注意到这题的查询很简单,修改很特殊
修改特殊在其没有改变相同颜色之间的相对顺序,所以可以考虑对于每个颜色开一个vector记录即可
4.矩形确定两维后o(n)处理 常用思路
5.
6.序列问题我们要考虑一下差分 之后就简单了