Bzoj 3050: [Usaco2013 Jan]Seating(线段树裸题,然而区间修改标记下放和讨论Push_up很揪心)

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Bzoj 3050: [Usaco2013 Jan]Seating(线段树裸题,然而区间修改标记下放和讨论Push_up很揪心)相关的知识,希望对你有一定的参考价值。

题目链接

题意:开始有一个空白的区间,每次可能进行两个操作:A 将一个长度为p的区间加入一段连续空白的位置 L:一个区间恢复空白;要求出A不能进行的次数。

非常裸的线段树题目,用线段树统计最大的空白区间,每个节点需要记录当前区间的最长空白区间,从左端开始的最长空白区间,从右端开始的最长空白区间。Push_up的时候要讨论下,可以分别取[l,mid]和[mid+1,r]的最大空白区间,也可以用[l,mid]的从右端开始的最长空白区间+[mid+1,r]从左端开始的最大空白区间。

每次A的时候,就查询一下当前能装下p的空白区间中最靠左的位置(用一个全局变量ans统计下),如果根节点的最长空白区间>=p,就把[ans,ans+p-1]变成被占有的状态,否则就在答案中++;如果是L,那就更简单,直接区间修改(听说不打标记能得的分比我这个考场未调试直接爆0的分高?)。标记的下方都是基本功了(一定是当前节点已经修改而子区间未修改)。

技术分享
 1 #include<iostream>
 2 #include<cstring>
 3 #include<cstdio>
 4 #define l i<<1
 5 #define r i<<1|1
 6 #define mid (x+y)/2
 7 #define lson x,mid
 8 #define rson mid+1,y
 9 using namespace std;
10 const int inf=0x7fffffff;
11 const int N=500005;
12 struct hp{int w,p,li,ri,size,delta;}a[N<<2];
13 int ans;
14 inline int in()
15 {    int x=0; char ch=getchar();    while (ch<0||ch>9) ch=getchar();
16     while (ch>=0&&ch<=9) x=x*10+ch-0,ch=getchar();return x;}
17 inline int get(){char ch=getchar();while (ch!=A&&ch!=L) ch=getchar();return ch==A;}
18 void build(int i,int x,int y)
19 {    a[i]=(hp){y-x+1,x,y-x+1,y-x+1,y-x+1,-1};
20     if (x==y) return;build(l,lson); build(r,rson);
21 }
22 void pushdown(int i,int x,int y)
23 {    int c=a[i].delta; a[i].delta=-1;a[l].delta=a[r].delta=c;
24     if (c){a[l].w=a[l].li=a[l].ri=0,a[l].p=inf;a[r].w=a[r].li=a[r].ri=0,a[r].p=inf;}
25     else{a[l].w=a[l].li=a[l].ri=mid-x+1,a[l].p=x;a[r].w=a[r].li=a[r].ri=y-mid,a[r].p=mid+1;}
26 }
27 inline hp updata(hp A,hp B,int x,int y)
28 {    hp c; c.delta=-1;c.size=A.size+B.size;
29     if (!A.w) c.w=B.w,c.li=0,c.ri=B.ri,c.p=B.p;
30     else if (!B.w) c.w=A.w,c.li=A.li,c.ri=0,c.p=A.p;
31     else{    c.li=A.li+(A.li==A.size?B.li:0);
32               c.ri=B.ri+(B.ri==B.size?A.ri:0);
33               if (A.w>=B.w) c.w=A.w,c.p=A.p;
34               else c.w=B.w,c.p=B.p;
35               if (A.ri+B.li>c.w||(A.ri+B.li==c.w&&mid-A.ri+1<c.p))
36             c.w=A.ri+B.li,c.p=mid-A.ri+1;
37         }return c;
38 }
39 void insert(int i,int x,int y,int s,int t,int k)
40 {    if (x>=s&&y<=t)
41     { if (k) a[i]=(hp){0,inf,0,0,y-x+1,1};
42       else a[i]=(hp){y-x+1,x,y-x+1,y-x+1,y-x+1,0};return;}    
43     if (a[i].delta!=-1) pushdown(i,x,y);
44     if (s<=mid) insert(l,lson,s,t,k);if (t>mid) insert(r,rson,s,t,k);
45     a[i]=updata(a[l],a[r],x,y);
46 }
47 void query(int i,int x,int y,int k){
48     if (x==y){ans=x; return;}
49     if (a[i].delta!=-1) pushdown(i,x,y);
50     if (a[l].w>=k) query(l,lson,k);
51     else if (a[l].ri+a[r].li>=k){
52       ans=mid-a[l].ri+1;
53       return;
54     }else query(r,rson,k);
55 }
56 int main()
57 {    int n=in(),m=in();
58     build(1,1,n); int tot=0;
59     while (m--)
60     { int opt=get();
61       if (opt)
62       {    int x=in();if (!x) continue;
63           if (a[1].w<x) tot++;
64           else {     query(1,1,n,x);
65                     insert(1,1,n,ans,ans+x-1,1);
66              }}
67           else{    int x=in(),y=in();insert(1,1,n,x,y,0);}
68     
69     }
70     cout<<tot<<endl;
71 }
AC Code

调试能力有待提升。

以上是关于Bzoj 3050: [Usaco2013 Jan]Seating(线段树裸题,然而区间修改标记下放和讨论Push_up很揪心)的主要内容,如果未能解决你的问题,请参考以下文章

[BZOJ 3048][Luogu P3069][USACO2013 Jan]Cow Lineup

[bzoj3048] [Usaco2013 Jan]Cow Lineup

bzoj 4506: [Usaco2016 Jan]Fort Moo

[BZOJ1677][Usaco2005 Jan]Sumsets 求和

bzoj 1783: [Usaco2010 Jan]Taking Turns

BZOJ 3887[Usaco2015 Jan]Grass Cownoisseur