桌子上零散地放着若干个盒子,盒子都平行于墙。桌子的后方是一堵墙。如图所示。现在从桌子的前方射来一束平行光, 把盒子的影子投射到了墙上。问影子的总宽度是多少?
桌子上零散地放着若干个盒子,盒子都平行于墙。桌子的后方是一堵墙。如图所示。现在从桌子的前方射来一束平行光, 把盒子的影子投射到了墙上。问影子的总宽度是多少?
第1行:3个整数L,R,N。-100000 <=L<=R<= 100000,表示墙所在的区间;1<=N<=100000,表示盒子的个数
接下来N行,每行2个整数BL, BR,-100000 <=BL<=BR<= 100000,表示一个盒子的左、右端点(左闭右开)
第1行:1个整数W,表示影子的总宽度。
Copy (如果复制到控制台无换行,可以先粘贴到文本编辑器,再复制)
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
【盒子的个数】
桌子上零散地放着若干个盒子,盒子都平行于墙。桌子的后方是一堵墙。如图所示。问从桌子前方可以看到多少个盒子?假设人站得足够远。
第1行:3个整数L,R,N。-100000 <=L<=R<= 100000,表示墙所在的区间;1<=N<=100000,表示盒子的个数
接下来N行,每行2个整数BL, BR,-100000 <=BL<=BR<= 100000,表示一个盒子的左、右端点(左闭右开)。越在前面输入的盒子越排在离墙近的位置,后输入的盒子排在离墙远的位置。
第1行:1个整数M,表示可看到的盒子个数。
Copy (如果复制到控制台无换行,可以先粘贴到文本编辑器,再复制)
1 10 5
2 6
3 6
4 6
1 2
3 6
3
这两道题很久以前就AC了,现在来当作模板题总结一下线段树的写法。
对于这两道孪生题目,也是不能说什么了……连图都节约资源用同一张……那么就总结一下吧!
对于第一题,相较于第二题还是很简单的,先建造出[L,R]的线段树(建树就不慢慢说了),然后用一个成员p记录区间状态:1=>全盖、0=>全裸、-1=>半盖半裸(有点像四象树)。
每次如果完全覆盖一个区间,不管怎样都将这个区间标记为全盖,然后返回。而如果无法完全覆盖,就分成左子区间和右子区间,递归操作。
但请注意,因为每次覆盖时都使用了‘懒操作’(lazy),其实我们只改变了最大一个区间的状态值,每次递归时需要将新的状态传递给儿子,并改变儿子,才能避免出错。同时,进行最后的查询用递归固然方便,但每次都有可能花费O(n)的时间,对于多次操作,我们可以新增一个成员sum,记录区间内的影子宽度,方便查询,不过要记得和p一起维护哦。
#include
#include
using namespace std;
const int M=100000;
struct node
{
int p,l,r;
}A[8*M+5];
int K[M+5][2];
int ml,mr,n;
void make(int i,int l,int r)
{
A[i].l=l;
A[i].r=r;
if(l==r)return;
make(i*2,l,((l+r)>>1));
make(i*2+1,((l+r)>>1)+1,r);
}
void insert(int q,int l,int r)
{
if(l<=A[q].l&&r>=A[q].r)
{
A[q].p=A[q].r-A[q].l+1;
return;
}
if(A[q].l>r||A[q].r
而对于第二题,我们必须换一种思路。我们这次的小p就不能只承担0、1、-1的任务了,它现在有很多种状态:a(a>0)表示区间的盒子全为a这一个、0表示区间没有任何盒子、-1表示区间内盒子混杂,不止一个。然后每次用同样的方法去将一个区间进行覆盖(同样需要下传p)。然后最后的时候,实在没办法使用可爱的sum(因为盒子被遮挡,可能在区间内不连续,甚至被隔成几段),我们进行一次O(n)的递归,将它们标记进数组就可以用一次循环进行统计了。
#include
#include
using namespace std;
const int M=100000;
struct node
{
int color,l,r;
}A[8*M+5];
int K[M+5][2];
int vis[M+5];
int ml,mr,n,ans;
void make(int i,int l,int r)
{
A[i].l=l;
A[i].r=r;
if(l==r)return;
make(i*2,l,((l+r)>>1));
make(i*2+1,((l+r)>>1)+1,r);
}
void insert(int q,int l,int r,int c)
{
if(l<=A[q].l&&r>=A[q].r)
{
A[q].color=c;
return;
}
if(A[q].l>r||A[q].r=0)
{
A[2*q].color=A[2*q+1].color=A[q].color;
A[q].color=-1;
}
if(A[q].l0)
{
if(!vis[A[q].color])
{
ans++;
vis[A[q].color]=1;
}
}
else
{
if(A[q].color==-1)
{
sum(2*q);
sum(2*q+1);
}
}
}
int main()
{
scanf("%d%d%d",&ml,&mr,&n);
mr--;
for(int i=1;i<=n;i++)
{
scanf("%d%d",&K[i][0],&K[i][1]);
K[i][1]--;
}
make(1,ml,mr);
for(int i=1;i<=n;i++)
insert(1,K[i][0],K[i][1],i);
sum(1);
printf("%d",ans);
}