Lflame

【2016/3/6考题 \ bzoj3838】Raper 线段树神题....

    虽然说是神题..我觉得还是因为我太弱啦...

    题意:

    你需要生产k张光盘。每张光盘需要经过两道工序:先在A工厂进行挤压,然后送到B工厂涂上反光层。

    共有n天时间,你知道每天A,B两家工厂的收费。一家工厂一天只能对一张光盘进行操作。同一天内一张光盘先后在A,B工厂被操作是允许的。你可以假定将只经过A操作的半成品暂存起来不需花费额外代价。

求出生产k张光盘的最小总花费。

    (n,k <= 500000  , bz总时限 60 s)


    首先,我们可以将其转化为括号序列,'('表示 A 工厂做操作,')'表示 B 工厂做操作,那么问题转化为求一个类似于 "()()()()()()()()...."的括号序列的一个合法子序列,使得子序列中有 k 个括号对且代价和最小。

    考虑每次选出和尽量小的两个括号,显然,我们只需要每时每刻保证选出的括号序列合法,即可得到最优解。也就是说,将括号序列转化为+-1过后,每一个前缀和都需要大于等于 0。

    设 s[] 为前缀和。如果我们选出了 "()" 的两个括号,则会使得这两个括号间的 s 加 1;如果我们选出了")("的两个括号,则会使得这两个括号间的 s 减 1,也就是说我们要选这两个括号的前提是其间的 s 最小值大于 0。

  

    好的,来理一理思路,我们现在要做的是支持做两个操作 :找到添加后合法的两个括号,以及修改连续一段的 s 值。于是考虑用线段树来维护。

    由于有区间修改,不可以直接维护选取")("的最优括号使得其间的 s 最小值大于 0 ,因为这样的信息是需要一直向下修改到叶子结点才行的。

    那么我们换一种方式,对于线段树的每个结点 t ,存下来 t 所管理的区间[ l , r ] 中选取 ")(" 的最优括号,使得括号间的 s 最小值大于 [l , r] 间的 s 最小值。这样的话,区间修改时,完整的被覆盖到的区间信息并不会被影响,所以支持区间修改。但是我们需要的并不是这个呀 ? 我们在位置 0 增加一个 0,那么线段树根节点所管理的区间的 s 最小值一定为 0,这便是我们需要的。

    这道题的思路便是这样,自己 YY 一下便可以搞出来了。

    

    不想自己 YY 的话,再继续看吧....

    具体来讲,令 A 为选取的左括号, B 为选取的右括号。那么以下为具体需要存储的信息。 ( %%% Claris )

    va:A≤B情况的最优解。

    vb:A>B情况的最优解,且满足[A,B−1]的区间s s最小值大于当前区间的s最小值。

    vc:A>B情况的最优解。

    aa:区间内代价最小的A。

    ab:区间内代价最小的B。

    ba:区间内代价最小的A,满足[st,A−1]的区间s最小值大于区间s最小值。

    bb:区间内代价最小的B,满足[B,en]的区间s s最小值大于区间s最值。

    vm:区间s最小值。

    tag:区间增量标记。

    只需要维护这些即可...

    

#include<iostream>

#include<cstdio>

#include<cstring>

#include<algorithm>

#define mid ((ll+rr)>>1)

using namespace std;


int K , n ;

int A[500005] , B[500005] , T[500005];

const int INF=(1<<30)-1 ;


struct couples

{

int l,r ;

couples(int _l=0,int _r=0) { l=_l , r=_r ; }

};


couples operator+ (const couples &a,const couples &b)

{

if(A[a.l]+B[a.r]<A[b.l]+B[b.r])return a;

return b;

}


bool operator==(const couples &a,const couples &b)

{

return a.l==b.l && a.r==b.r ;

}


//%%%%%%%%%%Claris

struct Segment_Tree

{

int ndnum , lc[1000005] , rc[1000005] , aa[1000005] , ab[1000005] , ba[1000005] , bb[1000005] , vm[1000005] ;

int tag[1000005] , root;

couples va[1000005],vb[1000005],vc[1000005] ;

inline int news(){ return ++ndnum ; }


void update(int s){

va[s]=va[lc[s]]+va[rc[s]]+couples(aa[lc[s]],ab[rc[s]]) , vc[s]=vc[lc[s]]+vc[rc[s]]+couples(aa[rc[s]],ab[lc[s]]) , vb[s]=vb[lc[s]]+vb[rc[s]];

aa[s]=(A[aa[lc[s]]]>A[aa[rc[s]]]?aa[rc[s]]:aa[lc[s]]) ;

ab[s]=(B[ab[lc[s]]]>B[ab[rc[s]]]?ab[rc[s]]:ab[lc[s]]) ;

if(vm[lc[s]]<vm[rc[s]]){

vb[s]=vb[s]+vc[rc[s]]+couples(aa[rc[s]],bb[lc[s]]) ;

ba[s]=ba[lc[s]] , bb[s]=(B[ab[rc[s]]]<B[bb[lc[s]]]?ab[rc[s]]:bb[lc[s]]) ;

vm[s]=vm[lc[s]] ;

}

if(vm[lc[s]]>vm[rc[s]]){

vb[s]=vb[s]+vc[lc[s]]+couples(ba[rc[s]],ab[lc[s]]) ;

ba[s]=(A[ba[rc[s]]]<A[aa[lc[s]]]?ba[rc[s]]:aa[lc[s]]) , bb[s]=bb[rc[s]] ;

vm[s]=vm[rc[s]] ;

}

if(vm[lc[s]]==vm[rc[s]]){

vb[s]=vb[s]+couples(ba[rc[s]],bb[lc[s]]) ;

ba[s]=ba[lc[s]] , bb[s]=bb[rc[s]] ;

vm[s]=vm[lc[s]] ;

}

}


void tag_it(int s,int val){

if(!s)return ;

vm[s]+=val , tag[s]+=val ;

}


void pushdown(int s){

if(tag[s]){

tag_it(lc[s],tag[s]) , tag_it(rc[s],tag[s]) ;

tag[s]=0 ;

}

}


void build(int s,int ll,int rr)

{

if(ll==rr){

aa[s]=ab[s]=ba[s]=ll ;

va[s]=couples(ll,ll) ;

return ;

}

lc[s]=news() , rc[s]=news() ;

build(lc[s],ll,mid) , build(rc[s],mid+1,rr) ;

update(s) ;

}


int c_pos ;

void change_it(int s,int ll,int rr){

pushdown(s) ;

if(ll==rr)return ;

if(c_pos<=mid)change_it(lc[s],ll,mid) ;

elsechange_it(rc[s],mid+1,rr) ;

update(s) ;

}


int a_l , a_r , a_num ;

void add(int s,int ll,int rr) {

if(ll>a_r || rr<a_l)return ;

pushdown(s) ;

if(ll>=a_l && rr<=a_r){

tag_it(s,a_num) ;

return ;

}

add(lc[s],ll,mid) , add(rc[s],mid+1,rr) ;

update(s) ;

}


void init()

{

root=news() ;

build(root,0,n) ;

}

}ST;


void solve()

{

ST.init() ;

long long ans=0 ;

while(K--){

couples t=ST.va[ST.root]+ST.vb[ST.root] ;

couples tmp=ST.vb[ST.root] ;

int x=t.l , y=t.r ;

ans+=A[x]+B[y] ;

A[x]=INF , ST.c_pos=x ;

ST.change_it(ST.root,0,n) ;

B[y]=INF , ST.c_pos=y ;

ST.change_it(ST.root,0,n) ;

if(t==tmp){

ST.a_l=y , ST.a_r=x-1 , ST.a_num=-1 ;

if(ST.a_l<=ST.a_r){

ST.add(ST.root,0,n) ;

}

}

else{

ST.a_l=x , ST.a_r=y-1 , ST.a_num=1 ;

if(ST.a_l<=ST.a_r){

ST.add(ST.root,0,n) ;

}

}

}

printf("%lld\n",ans) ;

}


int main()

{

scanf("%d%d",&n,&K) ;

for(int i=1;i<=n;++i)scanf("%d",&A[i]) ;

for(int i=1;i<=n;++i)scanf("%d",&B[i]);

A[0]=B[0]=INF ;

solve() ;

return 0 ;

}


评论(1)

热度(1)