您的位置:首页 > 其它

JZOJ 4883 【NOIP2016提高A组集训第12场11.10】灵知的太阳信仰

2016-11-14 20:58 411 查看

灵知的太阳信仰

题目大意

给出长度为N的序列P和K,现在要将序列分成若干段,必须满足每一段不存在一对(i,j),使得Pi=Pj(即每一段不存在两个相同的Pi),那么这段序列的割分代价就为这段序列中最大的Ki值。现在要将序列分成若干段,求最小的割分代价之和。

数据范围

N≤105,1≤Pi≤n,1≤Ki≤2∗104

题解

设Fi表示以i为当前最后一段的最后一个时割分代价之和的最小值,转移很显然,这儿就不写了。

求出对于每一个Pi上一次Pj=Pi的j的位置,这样就可以知道每一次最前可以由前面的哪个Fj转移过来。

由Fj转移到Fi−1的代价为max(Kj+1 ,..., Ki−1),变成转移到Fi后,代价为max(Kj+1 ,..., Ki),只多了一个Ki,那显然我们可以用一棵线段树来维护三个值:该段区间内Fi最小值,该段区间内转移代价最小值,Fi+转移代价的最小值。每次转移log N的时间复杂度,维护也是log N的时间复杂度,这样就可以将时间复杂度降到O(N log N)了。

Code(Pascal)

const
maxn=maxlongint;
var
n,m,j,k,l,i,o,left,wz:longint;
mz,mi:array[0..120000] of longint;
tr:array[0..1050000,1..3] of int64;
last,dq,la,f:array[0..1020000] of int64;
function max(a,b:int64):int64;
begin
if a>b then exit(a) else exit(b);
end;
function min(a,b:int64):int64;
begin
if a<b then exit(a) else exit(b);
end;
procedure jl(o,l,r:longint);
var
mid:longint;
begin
tr[o,1]:=maxn;
tr[o,2]:=0;
tr[o,3]:=maxn;
if l=r then exit;
mid:=(l+r) div 2;
jl(o*2,l,mid);
jl(o*2+1,mid+1,r);
end;
procedure down(o:longint);
var
ls,rs:longint;
begin
ls:=2*o;
rs:=ls+1;
tr[ls,2]:=la[o];
tr[rs,2]:=la[o];
tr[ls,3]:=tr[ls,1]+la[o];
tr[rs,3]:=tr[rs,1]+la[o];
la[ls]:=la[o];
la[rs]:=la[o];
la[o]:=0;
end;
procedure up(o:longint);
var
ls,rs:longint;
begin
ls:=o*2;
rs:=ls+1;
tr[o,1]:=min(tr[ls,1],tr[rs,1]);
tr[o,3]:=min(tr[ls,3],tr[rs,3]);
tr[o,2]:=min(tr[ls,2],tr[rs,2]);
end;
procedure gx(o,l,r,ll,rr,kk:int64);
var
mid,ls,rs:longint;
begin
if (l=ll) and (r=rr) then
begin
la[o]:=kk;
tr[o,2]:=kk;
tr[o,3]:=tr[o,1]+tr[o,2];
exit;
end;
mid:=(l+r) div 2;
ls:=o*2; rs:=ls+1;
if la[o]>0 then down(o);
if ll>mid then gx(rs,mid+1,r,ll,rr,kk)
else if rr<=mid then gx(ls,l,mid,ll,rr,kk)
else
begin gx(ls,l,mid,ll,mid,kk); gx(rs,mid+1,r,mid+1,rr,kk); end;
up(o);
end;
function xz(o,l,r,kk:Longint):longint;
begin
if l=r then exit(l);
if la[o]>0 then down(o);
if tr[o*2,2]<kk then xz:=xz(o*2,l,(l+r) div 2,kk)
else xz:=xz(o*2+1,(l+r) div 2+1,r,kk);
up(o);
end;
procedure ddxg(o,l,r,k:longint);
var mid:longint;
begin
mid:=(l+r) div 2;
if l=r then
begin
tr[o,1]:=f[k];
tr[o,3]:=f[k];
exit;
end;
if la[o]>0 then down(o)
else if k<=mid then ddxg(o*2,l,mid,k)
else ddxg(o*2+1,mid+1,r,k);
up(o);
end;
function qz(o,l,r,ll,rr:longint):int64;
var
mid:longint;
begin
if (l=ll) and (r=rr) then exit(tr[o,3]);
mid:=(l+r) div 2;
if la[o]>0 then down(o);
if ll>mid then qz:=qz(o*2+1,mid+1,r,ll,rr)
else if rr<=mid then qz:=qz(o*2,l,mid,ll,rr)
else qz:=min(qz(o*2,l,mid,ll,mid),qz(o*2+1,mid+1,r,mid+1,rr));
up(o);
end;
begin
readln(n);
inc(n);
mz[i]:=-1;
for i:=2 to n do
begin
readln(mz[i],mi[i]);
last[i]:=dq[mz[i]];
dq[mz[i]]:=i;
end;
jl(1,1,n);
left:=1;
f[1]:=mi[1];
ddxg(1,1,n,1);
for i:=2 to n do
begin
left:=max(left,last[i]);
wz:=xz(1,1,n,mi[i]);
if wz<i then
gx(1,1,n,wz,i-1,mi[i]);
f[i]:=qz(1,1,n,left,i-1);
ddxg(1,1,n,i);
end;
writeln(f
);
end.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: