影子的宽度&&盒子的个数

影子的宽度

问题描述

桌子上零散地放着若干个盒子,盒子都平行于墙。桌子的后方是一堵墙。如图所示。现在从桌子的前方射来一束平行光, 把盒子的影子投射到了墙上。问影子的总宽度是多少?

enter image description here

输入格式

第1行:3个整数L,R,N。-100000 ≤L≤R≤ 100000,表示墙所在的区间;1≤N≤100000,表示盒子的个数 接下来N行,每行2个整数BL, BR,-100000 ≤BL≤BR≤ 100000,表示一个盒子的左、右端点

输出格式

第1行:1个整数W,表示影子的总宽度。

样例输入

Sample Input 1

0 7 2

1 2

4 5

Sample Input 2

-10 10 2

-5 2

-2 2

Sample Input 3

-10 10 3

-7 0

-4 9

-4 2

Sample Input 4

-100 100 3

-7 2

5 9

2 5

Sample Input 5

-50 50 4

-2 4

0 6

9 10

-5 30

样例输出

Sample Output 1

2

Sample Output 2

7

Sample Output 3

16

Sample Output 4

16

Sample Output 5

35

题解

用线段树维护左闭右开的区间 [l,r)影子的总宽度,标记flag表示这段区间是否全被影子覆盖。下传标记的时候,传完后不能置为0。

 1 #include <cstdio>
 2 const int maxn=100000;
 3 struct node{
 4     int num;
 5     bool lb,rb,flag;
 6 }f[5000005];
 7 int n,L,R,s,t;
 8 int max(int x,int y)
 9 {
10     return x>y?x:y;
11 }
12 void pushdown(int l,int r,int id)
13 {
14     if (!f[id].flag) return;
15     int ls=id<<1,rs=ls|1,mid=(l+r)>>1;
16     f[ls].num=mid-l;
17     f[rs].num=r-mid;
18     f[ls].flag=f[rs].flag=1;
19     f[ls].lb=f[ls].rb=f[rs].lb=f[rs].rb=1;
20 //    f[id].flag=0;      // 不知道为什么写了这句会WA 
21     return;
22 }
23 void modify(int l,int r,int id)  //  [ l , r )
24 {
25     pushdown(l,r,id);
26     if (s<=l && r<=t)
27     {
28         f[id].num=r-l;
29         f[id].lb=f[id].rb=1;
30         f[id].flag=1;
31         return;
32     }
33     f[id].flag=0;
34     int ls=id<<1,rs=ls|1,mid=(l+r)>>1;
35     if (s<mid) modify(l,mid,ls);  // 注意!!!由于是左闭右开区间,这里没有等号 
36     if (t>mid) modify(mid,r,rs);
37     f[id].lb=f[ls].lb;
38     f[id].rb=f[rs].rb;
39     f[id].num=f[ls].num+f[rs].num;
40 //    pushdown(l,mid,ls);
41 //    pushdown(mid,r,rs);
42     return;
43 }
44 int main()
45 {
46     int i,j;
47     scanf("%d%d%d",&L,&R,&n);
48     L+=maxn;  R+=maxn;
49     while (n--)
50     {
51       scanf("%d%d",&s,&t);      
52       s+=maxn,t+=maxn;
53       modify(L,R,1);
54     }      
55     printf("%d",f[1].num);
56     return 0;
57 }

盒子的个数

问题描述

桌子上零散地放着若干个盒子,盒子都平行于墙。桌子的后方是一堵墙。如图所示。问从桌子前方可以看到多少个盒子?假设人站得足够远。 enter image description here

输入格式

第1行:3个整数L,R,N。-100000 ≤L≤R≤ 100000,表示墙所在的区间;1≤N≤100000,表示盒子的个数 接下来N行,每行2个整数BL, BR,-100000 ≤BL≤BR≤ 100000,表示一个盒子的左、右端点。越在前面输入的盒子越排在离墙近的位置,后输入的盒子排在离墙远的位置。

输出格式

第1行:1个整数M,表示可看到的盒子个数。

样例输入

1 10 5

2 6

3 6

4 6

1 2

3 6

样例输出

3

题解

做出前面那题,这题就比较简单了。

易得,一个离墙最远的盒子不会被其它盒子挡住。由此可推,对于任意一个盒子i,设它到墙的距离为d[i],如果所有d[j]>d[i]的盒子j不能把盒子i完全挡住,那么盒子i就可以被看到。

回忆前一题,每添加一个盒子,就会把线段树的一些区间完全覆盖,那么我们倒过来,从n到1添加盒子,在添加第i个盒子前,线段树上被覆盖的区间就是被挡住看不到的区间。要判断一个盒子能不能被看到,只要在这个盒子覆盖区间之前,判断一下要被覆盖的区间是不是已经被完全覆盖,如果没有被完全覆盖,这个盒子就可以被看到。

 1 #include <cstdio>
 2 const int maxn=100000;
 3 struct node{
 4     int num;
 5     bool lb,rb,flag;
 6 }f[5000005];
 7 int n,L,R,s,t,bl[100005],br[100005],ans,p;
 8 bool cansee[100005];
 9 int max(int x,int y)
10 {
11     return x>y?x:y;
12 }
13 void pushdown(int l,int r,int id)
14 {
15     if (!f[id].flag) return;
16     int ls=id<<1,rs=ls|1,mid=(l+r)>>1;
17     f[ls].num=mid-l;
18     f[rs].num=r-mid;
19     f[ls].flag=f[rs].flag=1;
20     f[ls].lb=f[ls].rb=f[rs].lb=f[rs].rb=1;
21     return;
22 }
23 void modify(int l,int r,int id)  //  [ l , r )
24 {    
25     pushdown(l,r,id);
26     if (s<=l && r<=t)
27     {
28         if (f[id].num<r-l) cansee[p]=1;
29         f[id].num=r-l;
30         f[id].lb=f[id].rb=1;
31         f[id].flag=1;
32         return;
33     }
34     f[id].flag=0;
35     int ls=id<<1,rs=ls|1,mid=(l+r)>>1;
36     if (s<mid) modify(l,mid,ls);
37     if (t>mid) modify(mid,r,rs);
38     f[id].lb=f[ls].lb;
39     f[id].rb=f[rs].rb;
40     f[id].num=f[ls].num+f[rs].num;
41     return;
42 }
43 int main()
44 {
45     int i,j;
46     scanf("%d%d%d",&L,&R,&n);
47     L+=maxn;  R+=maxn;
48     for (i=1;i<=n;i++)
49       scanf("%d%d",&bl[i],&br[i]),
50       bl[i]+=maxn,br[i]+=maxn;
51     for (p=n;p>=1;p--)
52       s=bl[p],t=br[p],
53       modify(L,R,1);
54     for (i=1;i<=n;i++)
55       if (cansee[i])
56         ans++;
57     printf("%d
",ans);
58     return 0;
59 }
原文地址:https://www.cnblogs.com/rabbit1103/p/9550964.html