zoukankan      html  css  js  c++  java
  • 【BZOJ3050】【USACO 2013 Jan Gold金组】坐座位 Seating

    【USACO 2013 1月金组】seating

    时间限制: 1 Sec 内存限制: 128 MB

    题目描述

    为了赚更多的钱,奶牛场开了一间专门做奶昔的餐馆。这个餐馆有N个位子(1<=N<=500000)排成一行,开始时,位子都是空的。
    每天,有M个不同的事件按次序发生(1<=M<=300000).事件分为两类:
    1.举办一个party,这个party有p头奶牛(1<=p<=N),这p头奶牛只会坐在相邻的位子。如果没有p个连续的空位,则奶牛们会离开。如果有多个,奶牛们会选择起点编号最小的一段空位。
    2.区间[a,b]的奶牛们离开座位。(1<=a

    输入

    第一行:两个整数N,M。
    第二行到第M+1行:每一行表示一个事件,它要么是形如“A p”,表示有一个party,这个party有p头奶牛;要么是形如L a b 的一行,表示区间[a,b]的所有奶牛全部离开。

    输出

    一行,表示不满足要求的聚会个数。

    样例输入

    10 4
    A 6
    L 2 4
    A 5
    A 2

    样例输出

    1

    解题报告:

    某天考试题。。。
    比较裸的线段树题目,关键在于代码实现有点难(考试时没调出来)
    用线段树控制区间的删除与增加,
    每个线段树上节点,维护3个变量le,max,re。

    struct Node{
        int l,r;
        int le,re,max;
        int lz;
    }nodes[MAXN*5];

    他们分别表示该区间内部靠左的空间大小,区间中不与左右空区间接触的最大空区间大小,该区间内部靠右的空区间大小。
    每次updata操作这样写:

    inline void updata(int u){
        nodes[u].max=maxf(nodes[u<<1].max,nodes[(u<<1)+1].max);
        nodes[u].max=maxf(nodes[u].max,nodes[u<<1].re+nodes[(u<<1)+1].le);
        le[u]=nodes[u<<1].le;
        re[u]=nodes[(u<<1)+1].re;
        if(nodes[u<<1].le==nodes[u<<1].r-nodes[u<<1].l+1)
            le[u]+=nodes[(u<<1)+1].le;
        if(nodes[(u<<1)+1].re==nodes[(u<<1)+1].r-nodes[(u<<1)+1].l+1)
            re[u]+=nodes[u<<1].re;
    }

    lazy标记保存三个值,非别是0,1,2
    代表无操作,填满和清空

    const int REMOVE=2;
    const int FILL=1;

    下传lazy时这么写:

    inline void pushdown(int index){
        nodes[index<<1].lz=nodes[(index<<1)+1].lz=nodes[index].lz;
        if(nodes[index].lz==FILL){
            nodes[index<<1].le=nodes[index<<1].re=nodes[index<<1].max=0;
            nodes[(index<<1)+1].le=nodes[(index<<1)+1].re=nodes[(index<<1)+1].max=0;
        }
        else if(nodes[index].lz==REMOVE){
            nodes[index<<1].max=nodes[index<<1].re=nodes[index<<1].le
            =nodes[index<<1].r-nodes[index<<1].l+1;
            nodes[(index<<1)+1].max=nodes[(index<<1)+1].re=nodes[(index<<1)+1].le
            =nodes[(index<<1)+1].r-nodes[(index<<1)+1].l+1;
        }
        nodes[index].lz=0;
    }

    由于每次A操作要寻找一段最靠左长度为len的空区间
    因此多添加一个函数:

    int len;
    int query(int u){
        if(nodes[u].l==nodes[u].r)return nodes[u].l;
        if(nodes[u].lz)
            pushdown(u);
        if(nodes[u<<1].max>=len)return query(u<<1);
        else if(nodes[u<<1].re+nodes[(u<<1)+1].le>=len)
            return nodes[u<<1].r-nodes[u<<1].re+1;
        else return query((u<<1)+1);
    }

    此函数用于寻找长度为len的空区间左端点位置
    原理:在保持当前区间中最大空区间长度大于len时尽量向左儿子前进,最后找到的一定是最靠左的区间。

    下面发AC代码:

    #include<cstdio>
    const int MAXN=510000;
    const int MAXM=310000;
    const int REMOVE=2;
    const int FILL=1;
    inline int max(const int &a,const int &b)
    {return a<b?b:a;}
    inline int min(const int &a,const int &b)
    {return a<b?a:b;}
    inline void getint(int &t){
        register char c;t=0;
        do{c=getchar();}while(c<'0'||c>'9');
        while(c<='9'&&c>='0'){t=t*10+c-'0';c=getchar();}
    }
    struct Node{
        int l,r;
        int le,re,max;
        int lz;
    }nodes[MAXN*5];
    inline void pushdown(int index){
        nodes[index<<1].lz=nodes[(index<<1)+1].lz=nodes[index].lz;
        if(nodes[index].lz==FILL){
            nodes[index<<1].le=nodes[index<<1].re=nodes[index<<1].max=0;
            nodes[(index<<1)+1].le=nodes[(index<<1)+1].re=nodes[(index<<1)+1].max=0;
        }
        else if(nodes[index].lz==REMOVE){
            nodes[index<<1].max=nodes[index<<1].re=nodes[index<<1].le
            =nodes[index<<1].r-nodes[index<<1].l+1;
            nodes[(index<<1)+1].max=nodes[(index<<1)+1].re=nodes[(index<<1)+1].le
            =nodes[(index<<1)+1].r-nodes[(index<<1)+1].l+1;
        }
        nodes[index].lz=0;
    }
    inline void updata(int u){
        nodes[u].max=max(nodes[u<<1].max,nodes[(u<<1)+1].max);
               nodes[u].max=max(nodes[u].max,nodes[u<<1].re+nodes[(u<<1)+1].le);
        nodes[u].le=nodes[u<<1].le;
        nodes[u].re=nodes[(u<<1)+1].re;
        if(nodes[u<<1].le==nodes[u<<1].r-nodes[u<<1].l+1)
            nodes[u].le+=nodes[(u<<1)+1].le;
        if(nodes[(u<<1)+1].re==nodes[(u<<1)+1].r-nodes[(u<<1)+1].l+1)
            nodes[u].re+=nodes[u<<1].re;
    }
    void build(int u,int l,int r){
        nodes[u].l=l;
        nodes[u].r=r;
        nodes[u].le=nodes[u].re=nodes[u].max=r-l+1;
        if(l==r)return ;
        int mid=(l+r)>>1;
        build(u<<1,l,mid);
        build((u<<1)+1,mid+1,r);
    }
    int l,r,k;
    void fill(int u){
        if(nodes[u].r<l||nodes[u].l>r)return ;
        if(nodes[u].lz)
            pushdown(u);
        if(nodes[u].l>=l&&nodes[u].r<=r){
            nodes[u].lz=k;
            if(k==REMOVE)nodes[u].le=nodes[u].re=nodes[u].max=nodes[u].r-nodes[u].l+1;
            else nodes[u].le=nodes[u].re=nodes[u].max=0;
            return ;
        }
        fill(u<<1);
        fill((u<<1)+1);
        updata(u);
    }
    int len;
    int query(int u){
        if(nodes[u].l==nodes[u].r)return nodes[u].l;
        if(nodes[u].lz)
            pushdown(u);
        if(nodes[u<<1].max>=len)return query(u<<1);
        else if(nodes[u<<1].re+nodes[(u<<1)+1].le>=len)
            return nodes[u<<1].r-nodes[u<<1].re+1;
        else return query((u<<1)+1);
    }
    int main(){
        int n,m;
        getint(n),getint(m);
        build(1,1,n);
        int ans=0;
        register char o;
        register int a,b,c;
        for(int i=1;i<=m;i++){
            while((o=getchar())!='L'&&o!='A');
            if(o=='L'){
                getint(a);
                getint(b);
                l=a;
                r=b;
                k=REMOVE;
                fill(1);
            }else {
                getint(c);
                if(c>nodes[1].max){ans++;continue;}
                len=c;
                int pos=query(1);
                l=pos;
                r=pos+c-1;
                k=FILL;
                fill(1);
            }
        }
        printf("%d
    ",ans);
    }
    //ORZ GJY LJH  TSY SYK YLY GMR YMX

    此题在bzoj上每个点给了10秒的时限,但是在学校oj上只给一秒。。。
    于是就成了卡常神题 = =

    我从两天前开始就是一阵狂T,把能想到的inline,读入优化,等等全部写上,再把函数参数全改成全局变量,
    结果是这样的:
    哎
    = =
    心酸呐= =
    然后只好在群里求助大神,大神说加个注释就能保证卡过!
    于是加上:

    //ORZ GJY LJH  TSY SYK YLY GMR YMX

    然后果然交了两发就过了啊哈哈哈

  • 相关阅读:
    LeetCode Single Number
    Leetcode Populating Next Right Pointers in Each Node
    LeetCode Permutations
    Leetcode Sum Root to Leaf Numbers
    LeetCode Candy
    LeetCode Sort List
    LeetCode Remove Duplicates from Sorted List II
    LeetCode Remove Duplicates from Sorted List
    spring MVC HandlerInterceptorAdapter
    yum
  • 原文地址:https://www.cnblogs.com/Hineven/p/5843565.html
Copyright © 2011-2022 走看看