JZOJ 4867 【NOIP2016提高A组集训第8场11.5】心理学概论

心理学概论

题目大意

给出 N 个三元组{Ai, Bi , Ci },对于每一个三元组,有三个以下的操作:
<1>把 Ai 加入第一组内。
<2>把 Bi 加入第二组内。
<3>把 Ci 加入第三组内。
定义一个组的的代价为加入进该组的元素的最大值,问三组代价之和的最小值。

数据范围

对于100%的数据, 1N105 1Ai,Bi,Ci108

题解

首先先考虑以下二元组{ Ai , Bi }的情况,将二元组按照 Ai 的值从小到大排序,假设选择了第 i 个二元组的Ai作为第 1 组的代价,那么第1~ i -1个二元组当然也可以选入第一组,剩下的只能选入第二组,此时的总代价为 Ai + max ( Bi+1 , Bi+2 , ... , Bn ),枚举 i O( n )统计答案即可。

那现在由二元组换成三元组,一样的思想,按照Ai的值从小到大对三元组排序。
假如选择了第 i 组的Ai作为第一组的代价,那么第 1 ~i- 1 个三元组也可以选入第一组,剩下的第i+ 1 ~n组只能选入第二组和第三组,第 i +1~ n 组的Bi Ci 分开求其最小代价即可。

从大到小枚举 i ,从后往前做,每次都会将新的二元组{Bi, Ci }加入维护只选 Bi Ci 的最小值。关于从第 i +1~ n 个三元组中只选Bi Ci 时的最小代价,也就是关于二元组的求值,我们可以用一开始的方法,但因为我们要做N次,所以我们要用到线段树降低时间复杂度,同时我们可以避免排序。

线段树维护三个值:该段区间内 Bi 最小值,该段区间内 max ( Ci , Ci+1 , ... , Cn )的最小值(设前面那个式子的值为 Gi )以及每一种选法的最小代价(即 Bi + Gi+1 的最小值),对于每次加入一个新的二元组{ Bi , Ci },操作有两种,第一个插入一个 Bi ,第二个是将某一段 Gi 全部变为 Ci ,同时我们可以用二分求出需要更新的区间即可。

Code(Pascal)

const
    maxn=maxlongint;
var
    tr:array[0..4000000,1..5] of int64;
    ba:array[0..200000,1..3] of int64;
    pa:array[0..200000,1..2] of longint;
    d:array[0..150000] of longint;
    la:array[0..4000000] of int64;
    n,m,j,k,l,i,wz:longint;
    o,oo,ans,kk:int64;
function min(a,b:int64):int64;
    begin
        if a<b then exit(a)
        else exit(b);
    end;
function max(a,b:int64):int64;
    begin
        if a>b then exit(a)
        else exit(b);
    end;
procedure qsort(l,r:longint);
    var
        i,j,m:longint;
    begin
        i:=l;
        j:=r;
        m:=ba[(l+r) div 2,1];
        repeat
            while ba[i,1]<m do inc(i);
            while ba[j,1]>m do dec(j);
            if i<=j then
            begin
                ba[0]:=ba[i];
                ba[i]:=ba[j];
                ba[j]:=ba[0];
                inc(i);
                dec(j);
            end;
        until i>j;
        if l<j then qsort(l,j);
        if i<r then qsort(i,r);
    end;
procedure qsortll(l,r:longint);
    var
        i,j,m:longint;
    begin
        i:=l;
        j:=r;
        m:=pa[(l+r) div 2,1];
        repeat
            while pa[i,1]<m do inc(i);
            while pa[j,1]>m do dec(j);
            if i<=j then
            begin
                pa[0]:=pa[i];
                pa[i]:=pa[j];
                pa[j]:=pa[0];
                inc(i);
                dec(j);
            end;
        until i>j;
        if l<j then qsortll(l,j);
        if i<r then qsortll(i,r);
    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);
    begin
        tr[o*2,2]:=la[o];
        tr[o*2+1,2]:=la[o];
        tr[o*2,3]:=tr[o*2,1]+la[o];
        tr[o*2+1,3]:=tr[o*2+1,1]+la[o];
        la[o*2]:=la[o];
        la[o*2+1]:=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,2]:=min(tr[ls,2],tr[rs,2]);
        tr[o,3]:=min(tr[ls,3],tr[rs,3]);
    end;
function xz(o,l,r,kk:longint):longint;
    var
        mid:longint;
    begin
        if l=r then exit(l);
        mid:=(l+r) div 2;
        if la[o]>0 then down(o);
        if tr[o*2,2]<kk then exit(xz(o*2,l,mid,kk))
        else exit(xz(o*2+1,mid+1,r,kk));
        up(o);
    end;
function gx(o,l,r,ll,rr,bh:int64):int64;
    var
        mid,ls,rs:longint;
    begin
        if (l=ll) and (r=rr) then
        begin
            la[o]:=bh;
            tr[o,2]:=la[o];
            tr[o,3]:=tr[o,1]+la[o];
            exit;
        end;
        if la[o]>0 then down(o);
        mid:=(l+r) div 2;
        ls:=o*2;
        rs:=ls+1;
        if rr<=mid then gx(ls,l,mid,ll,rr,bh)
        else if ll>mid then gx(rs,mid+1,r,ll,rr,bh)
        else
        begin
            gx(ls,l,mid,ll,mid,bh);
            gx(rs,mid+1,r,mid+1,rr,bh);
        end;
        up(o);
    end;
procedure ddxg(o,l,r,kk:int64);
    var
        mid:longint;
    begin
        if l=r then
        begin
            tr[o,1]:=d[kk];
            tr[o,3]:=d[kk]+tr[o,2];
            exit;
        end;
        mid:=(l+r) div 2;
        if la[o]>0 then down(o);
        if kk<=mid then ddxg(o*2,l,mid,kk)
        else ddxg(o*2+1,mid+1,r,kk);
        up(o);
    end;
begin
    assign(input,'psy.in'); reset(input);
    assign(output,'psy.out'); rewrite(output);
    readln(n);
    for i:=1 to n do
    readln(ba[i,1],ba[i,2],ba[i,3]);
    qsort(1,n);
    ans:=ba[n,1];
    for i:=1 to n do
    begin
        pa[i,1]:=ba[i,2];
        pa[i,2]:=i;
    end;
    qsortll(1,n);
    oo:=1;
    kk:=0;
    for i:=1 to n do
    if pa[i,1]<>kk then
    begin
        inc(oo);
        d[oo]:=pa[i,1];
        kk:=pa[i,1];
        ba[pa[i,2],2]:=oo;
    end else ba[pa[i,2],2]:=oo;
    jl(1,1,oo);
    d[0]:=0;
    ddxg(1,1,oo,1);
    ba[0,1]:=0;
    for i:=n downto 1 do
    begin
        if ba[i,2]<>1 then
        begin
            wz:=xz(1,1,oo,ba[i,3]);
            if wz<ba[i,2] then
            gx(1,1,oo,wz,ba[i,2]-1,ba[i,3]);
        end;
        ddxg(1,1,oo,ba[i,2]);
        ans:=min(ans,ba[i-1,1]+tr[1,3]);
    end;
    writeln(ans);
end.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值