影子的宽度
问题描述
桌子上零散地放着若干个盒子,盒子都平行于墙。桌子的后方是一堵墙。如图所示。现在从桌子的前方射来一束平行光, 把盒子的影子投射到了墙上。问影子的总宽度是多少?
输入格式
第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 }
盒子的个数
问题描述
桌子上零散地放着若干个盒子,盒子都平行于墙。桌子的后方是一堵墙。如图所示。问从桌子前方可以看到多少个盒子?假设人站得足够远。
输入格式
第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 }