【BZOJ3050】Seating,线段树

来源:互联网 发布:linux informix客户端 编辑:程序博客网 时间:2024/06/04 01:19

传送门(权限题)


3050: [Usaco2013 Jan]Seating

Time Limit: 10 Sec Memory Limit: 128 MB
Submit: 132 Solved: 76
[Submit][Status][Discuss]
Description

To earn some extra money, the cows have opened a restaurant in their barn specializing in milkshakes. The restaurant has N seats (1 <= N <= 500,000) in a row. Initially, they are all empty. Throughout the day, there are M different events that happen in sequence at the restaurant (1 <= M <= 300,000). The two types of events that can happen are: 1. A party of size p arrives (1 <= p <= N). Bessie wants to seat the party in a contiguous block of p empty seats. If this is possible, she does so in the lowest position possible in the list of seats. If it is impossible, the party is turned away. 2. A range [a,b] is given (1 <= a <= b <= N), and everybody in that range of seats leaves. Please help Bessie count the total number of parties that are turned away over the course of the day.

m(m<=300,000)个操作。操作分2种:
1.A p,表示把编号最小的空着的长度为p的区间图上颜色。
2.L a b,表示把从a到b的区间(包括端点)全部擦干净(没颜色还是没颜色)。
Q:有多少个操作1不能实现?

Input

  • Line 1: Two space-separated integers, N and M.
  • Lines 2..M+1: Each line describes a single event. It is either a line of the form “A p” (meaning a party of size p arrives) or “L a b” (meaning that all cows in the range [a, b] leave).

Output

  • Line 1: The number of parties that are turned away.

Sample Input

10 4

A 6

L 2 4

A 5

A 2

INPUT DETAILS: There are 10 seats, and 4 events. First, a party of 6 cows arrives. Then all cows in seats 2..4 depart. Next, a party of 5 arrives, followed by a party of 2.

Sample Output

1

OUTPUT DETAILS: Party #3 is turned away. All other parties are seated.

HINT

样例解释:

首先将1~6图上颜色,再把2~4擦掉,这时不存在长度为5的空着的区间,该操作不能实现,跳过。最后把2~3图上颜色。所以不能实现的操作1有一个,即第三个操作。


写在前面:当时测试的时候被翻译坑了TAT,题意“找出所有可放的空闲中最左端的,没有可放的就ans++”理解成“从最左端空闲放,不能放就ans++”
思路:线段树吗,要记录的东西可能有点奇怪,是左、右端点各自所在的最大空闲ls,rs与整个区间内的最大空闲sum
对于查询操作,能不能放取决于[1,n]区间的最大空闲是否够,如果够就向下找,只有三种情况
1.左区间可以放,这时移到左节点继续找
2.1不满足时看看是不是能够放在中间,就是左边放一些右边放一些(仍是连续的),这就取决与左节点的右端最大空闲和右节点的左端最大空闲总和是否可以符合要求
3.1,2都不满足,移到右节点找
对于修改操作,我们往上返回左右节点信息时要注意我们要将父节点的三个信息改成什么,是如何由子节点的信息决定的,这里就不详细说明,留给大家自己思考,如果想不通可以看代码
注意:区间修改加lazy标记,注意lazy标记要分辨“未加过标记”“区间为0”“区间为1”
代码:

#include<bits/stdc++.h>using namespace std;int n,m,ans,p,x,y;char ch;struct os{    int ls,rs,sum,lazy;}tree[2000010];void pushdown(int now,int begin,int end){    if (tree[now].lazy==0||begin==end) return;    int mid=(begin+end)>>1;    if (tree[now].lazy==1)        tree[now<<1|1]=tree[now<<1]=(os){0,0,0,1};    else        tree[now<<1]=(os){mid-begin+1,mid-begin+1,mid-begin+1,-1},        tree[now<<1|1]=(os){end-mid,end-mid,end-mid,-1};    tree[now].lazy=0;}void pushup(int now,int begin,int end){    int mid=(begin+end)>>1;    tree[now].sum=max(max(tree[now<<1].rs+tree[now<<1|1].ls,tree[now<<1].sum),tree[now<<1|1].sum);    tree[now].ls=tree[now<<1].ls;    if (tree[now<<1].ls==mid-begin+1) tree[now].ls+=tree[now<<1|1].ls;    tree[now].rs=tree[now<<1|1].rs;    if (tree[now<<1|1].rs==end-mid) tree[now].rs+=tree[now<<1].rs;}void build(int now,int begin,int end){    tree[now]=(os){end-begin+1,end-begin+1,end-begin+1,0};    if (begin==end) return;    int mid=(begin+end)>>1;    build(now<<1,begin,mid);    build(now<<1|1,mid+1,end);}int find(int now,int begin,int end,int need){    if (begin==end) return end;    int mid=(begin+end)>>1;    if (tree[now<<1].sum>=need) return find(now<<1,begin,mid,need);    else if (tree[now<<1].rs+tree[now<<1|1].ls>=need) return mid+1-tree[now<<1].rs;    else return find(now<<1|1,mid+1,end,need);}void update(int now,int begin,int end,int l,int r,int num){    if (l<=begin&&end<=r)    {        if (!num) tree[now]=(os){end-begin+1,end-begin+1,end-begin+1,-1};        else tree[now]=(os){0,0,0,1};        return;    }    pushdown(now,begin,end);    int mid=(begin+end)>>1;    if (mid>=l) update(now<<1,begin,mid,l,r,num);    if (mid<r) update(now<<1|1,mid+1,end,l,r,num);    pushup(now,begin,end);}main(){    scanf("%d%d",&n,&m);    build(1,1,n);    for (int i=1;i<=m;i++)    {        ch=getchar();        while (ch!='A'&&ch!='L') ch=getchar();        if (ch=='A')        {            scanf("%d",&p);            if (tree[1].sum<p){ans++;continue;}            x=find(1,1,n,p);            update(1,1,n,x,x+p-1,1);        }        else scanf("%d%d",&x,&y),update(1,1,n,x,y,0);    }    printf("%d",ans);}
0 0
原创粉丝点击