bzoj3898: 打的士

Posted ccz181078

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了bzoj3898: 打的士相关的知识,希望对你有一定的参考价值。

Description

酒足饭饱之后。
一帮人都喝醉了。
嘛,由于酒驾查的很严格,所以说接下来就是送客人回家的难题了。
嘛,接下来就是操蛋的设定。
小T把喝醉的人分成了好多组,每一组要用一部车把他们送回家睡大觉。
然后呢,每一组可以租用的车子也是不一样的,具体而言,对于第i组,有T[i]种的车子(型号可能相同)来把他们送回去。当然咯,小T只需要安排一辆车子就可以送走这一组所有的人了。由于囊中羞射,小T一定只会每组安排一辆车。
更具体的,送回家的费用,是所有租用的车子里面,型号最大的和型号最小的车子,型号的差距。(尼玛,你这是啥题面啊,有TM啥关系啊
但是呢= =,由于喝醉的人是相继的醉,不可能啊出现如下场景:
“大家一起醉吧。”
“好!”
一杯而下,全倒了。。。
所以呢,这样动态的安排车子,又给小T加了不少麻烦。也就是说,小T需要处理如下两个操作。
1.有一组人醉倒了。
2.询问当前所有醉倒的人送回家的费用。
但是又出现了一个问题。
小A说:“你能解决,老子给你1000W。”
小T说:“你还不如把车子全租了。”
小A说:“………………”
小A思考了一下又说:“既然不能全租,那就来个限定吧,租车的型号必须大于等于L。”
小T给了小A一巴掌。。。。。。
“GFS就能拽?”

Input

第一行有一个正整数,N,表示操作的总数目。
接下来N行,每行首先包含了一个字母C或者Q。
如果是C,则表示,现在有一组人醉倒了,他们需要租车。C的后面有一个正整数T[]表示的是这一组有T[]部车子可以租。接下来有T[]个数字,分别表示他们可以租的车子的型号。
如果是Q,则后面有一个限制,L,表示对于当前所有已经醉的组,算出他们租车的最小费用。并且租车的最小型号是L。

Output

对于每一个Q操作,输出最小费用。如果无法安排,请阁下输出-1。
线段树维护一下选的最小标号为x时,最大标号的最小值以及它们的差的最小值,修改是区间对一个数取max,查询是一个后缀最大值。
#include<bits/stdc++.h>
const int inf=0x7fffffff;
char buf[10000000],*ptr=buf,ob[3000007],*op=ob;
int _(){
    int x=0;
    while(*ptr<48)++ptr;
    while(*ptr>47)x=x*10+*ptr++-48;
    return x;
}
void pr(int x){
    if(x<0)*op++=-,x=-x;
    int ss[15],sp=0;
    do ss[++sp]=x%10+48;while(x/=10);
    while(sp)*op++=ss[sp--];
    *op++=10;
}
int n,mem[1000007],*mp=mem;
int xs[1000007],xp=0;
int _l,_r,_a;
void mins(int&a,int b){if(a>b)a=b;}
int min(int a,int b){return a<b?a:b;}
int max(int a,int b){return a>b?a:b;}
struct node{
    node*lc,*rc;
    int L,R,M;
    int tp,mv,mxv,ans;
    void fil(int x){
        mv=mxv=x,tp=1;
        ans=x-R;
    }
    void chk(){
        if(mv>=_a)return;
        if(mxv<_a)return fil(_a);
        lc->chk();
        rc->chk();
        up();
    }
    void dn(){
        if(tp){
            lc->fil(mv);
            rc->fil(mv);
            tp=0;
        }
    }
    void up(){
        mv=min(lc->mv,rc->mv);
        mxv=max(lc->mxv,rc->mxv);
        ans=min(lc->ans,rc->ans);
    }
    void mxs(){
        if(mv>=_a)return;
        if(_l<=L&&R<=_r)return chk();
        dn();
        if(_l<=M)lc->mxs();
        if(_r>M)rc->mxs();
        up();
    }
    void que(){
        if(_l<=L)return mins(_a,ans);
        dn();
        if(_l<=M)lc->que();
        rc->que();
    }
}ns[2000007],*np=ns,*rt;
node*build(int L,int R){
    node*w=np++;
    w->L=xs[L],w->R=xs[R];
    if(L<R){
        int M=L+R>>1;
        w->M=xs[M];
        w->lc=build(L,M);
        w->rc=build(M+1,R);
        w->up();
    }else w->fil(xs[L]);
    return w;
}
void mxs(int l,int r){
    _l=xs[l],_r=xs[r],_a=xs[r];
    if(_r>=xs[xp])_r=xs[xp-1];
    if(_l<=_r)rt->mxs();
}
bool ed=0;
struct Q{
    int tp,v,*vs;
    void R(){
        tp=_()==C-48;
        v=_();
        if(tp){
            vs=mp,mp+=v;
            for(int i=0;i<v;++i)xs[xp++]=vs[i]=_();
            std::sort(vs,vs+v);
        }
    }
    void cal(){
        if(tp){
            ed=1;
            int px=0;
            for(int i=0;i<v;++i){
                int x=std::lower_bound(xs,xs+xp,vs[i])-xs;
                mxs(px,x);
                px=x+1;
            }
            mxs(px,xp);
        }else{
            _a=inf;
            _l=*std::lower_bound(xs,xs+xp,v);
            if(_l<xs[xp])rt->que();
            if(_a>1e9)_a=-1;
            if(!ed)_a=0;
            pr(_a);
        }
    }
}qs[200007];
int main(){
    fread(buf,1,sizeof(buf),stdin);
    n=_();
    for(int i=0;i<n;++i)qs[i].R();
    std::sort(xs,xs+xp);
    xp=std::unique(xs,xs+xp)-xs;
    xs[xp]=inf;
    rt=build(0,xp-1);
    for(int i=0;i<n;++i)qs[i].cal();
    fwrite(ob,1,op-ob,stdout);
    return 0;
}

 

以上是关于bzoj3898: 打的士的主要内容,如果未能解决你的问题,请参考以下文章

BZOJ 2243--染色(树链剖分)

bzoj 1002 轮状病毒

bzoj4028 [HEOI2015]公约数数列(分块+卡常?)

20151105noip膜你赛bzoj3652 bzoj3653

修道士和野人问题

bzoj4517: [Sdoi2016]排列计数