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

灵知的太阳信仰

题目大意

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

数据范围

N105 1Pin 1Ki2104

题解

Fi 表示以 i 为当前最后一段的最后一个时割分代价之和的最小值,转移很显然,这儿就不写了。
求出对于每一个Pi上一次 Pj = Pi j 的位置,这样就可以知道每一次最前可以由前面的哪个Fj转移过来。
Fj 转移到 Fi1 的代价为 max ( Kj+1 , ... , Ki1 ),变成转移到 Fi 后,代价为 max ( Kj+1 , ... , Ki ),只多了一个 Ki ,那显然我们可以用一棵线段树来维护三个值:该段区间内 Fi 最小值,该段区间内转移代价最小值, Fi +转移代价的最小值。每次转移 log N 的时间复杂度,维护也是log N 的时间复杂度,这样就可以将时间复杂度降到O( N log N <script type="math/tex" id="MathJax-Element-2852">N</script>)了。

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[n]);
end.
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值