您的位置:首页 > 其它

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

2016-11-11 12:17 405 查看

心理学概论

题目大意

给出N个三元组{Ai,Bi,Ci},对于每一个三元组,有三个以下的操作:

<1>把Ai加入第一组内。

<2>把Bi加入第二组内。

<3>把Ci加入第三组内。

定义一个组的的代价为加入进该组的元素的最大值,问三组代价之和的最小值。

数据范围

对于100%的数据,1≤N≤105,1≤Ai,Bi,Ci≤108。

题解

首先先考虑以下二元组{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.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: