校门外的树(线段树)
题目描述 Description
某校大门外长度为L的马路上有一排树,每两棵相邻的树之间的间隔都是1米。我们可以把马路看成一个数轴,马路的一端在数轴0的位置,另一端在L的位置;数轴上的每个整数点,即0,1,2,……,L,都种有一棵树。
由于马路上有一些区域要用来建地铁。这些区域用它们在数轴上的起始点和终止点表示。已知任一区域的起始点和终止点的坐标都是整数,区域之间可能有重合的部分。现在要把这些区域中的树(包括区域端点处的两棵树)移走。你的任务是计算将这些树都移走后,马路上还有多少棵树。
输入描述 Input Description
输入第一行有两个整数L(1<=L<=10000)和M(1<=M<=100),L代表马路的长度,M代表区域的数目,L和M之间用一个空格隔开。接下来的M行每行包含两个不同的整数,用一个空格隔开,表示一个区域的起始点和终止点的坐标。
输出描述 Output Description
输出包括一行,这一行只包含一个整数,表示马路上剩余的树的数目。
样例输入 Sample Input
500 3
150 300
100 200
470 471
样例输出 Sample Output
298
数据范围及提示 Data Size & Hint
【数据规模】
对于20%的数据,区域之间没有重合的部分;
对于其它的数据,区域之间有重合的情况。
//首先,不加标记一定是能过的。 //但如果想加标记的话要注意,这个标记应该是bool型的,表示这个节点是不是零 //代码通俗易懂 #include<iostream> #include<cstdio> using namespace std; int n,m,x,y; struct node { int l,r,dis;bool flag; }tre[400000]; void tree_flag(int now) { tre[now<<1].flag=true; tre[now<<1|1].flag=true;//标记下传左右孩子 tre[now<<1].dis=0; tre[now<<1|1].dis=0;//now没有了他的左右孩子一定没有了。 } void build(int now,int l,int r) { tre[now].l=l;tre[now].r=r; tre[now].flag=false;//建树的时候别忘了初始化 if(l==r) { tre[now].dis=1; return; } int mid=(l+r)>>1; build(now<<1,l,mid); build(now<<1|1,mid+1,r); tre[now].dis=tre[now<<1].dis+tre[now<<1|1].dis; } void Delete(int now,int l,int r) { if(tre[now].l==l&&tre[now].r==r) { tre[now].dis=0; tre[now].flag=true;//改标记 return; } if(tre[now].flag) tree_flag(now);//如果被改了就下传 int mid=(tre[now].l+tre[now].r)>>1; if(l>mid) Delete(now<<1|1,l,r); else if(r<=mid) Delete(now<<1,l,r); else { Delete(now<<1,l,mid); Delete(now<<1|1,mid+1,r); } tre[now].dis=tre[now<<1].dis+tre[now<<1|1].dis; } int main() { scanf("%d%d",&n,&m); build(1,0,n); for(int i=1;i<=m;i++) { scanf("%d%d",&x,&y); Delete(1,x,y); } printf("%d",tre[1].dis); return 0; }
另 附codevs1191代码(类似)
#include<iostream> #include<cstdio> using namespace std; int n,m,x,y; struct node { int l,r,dis;bool flag; }tre[4000000]; void tree_flag(int now) { tre[now<<1].flag=true; tre[now<<1|1].flag=true; tre[now<<1].dis=0; tre[now<<1|1].dis=0; } void build(int now,int l,int r) { tre[now].l=l;tre[now].r=r; tre[now].flag=false; if(l==r) { tre[now].dis=1; return; } int mid=(l+r)>>1; build(now<<1,l,mid); build(now<<1|1,mid+1,r); tre[now].dis=tre[now<<1].dis+tre[now<<1|1].dis; } void Delete(int now,int l,int r) { if(tre[now].l==l&&tre[now].r==r) { tre[now].dis=0; tre[now].flag=true; return; } if(tre[now].flag) tree_flag(now); int mid=(tre[now].l+tre[now].r)>>1; if(l>mid) Delete(now<<1|1,l,r); else if(r<=mid) Delete(now<<1,l,r); else { Delete(now<<1,l,mid); Delete(now<<1|1,mid+1,r); } tre[now].dis=tre[now<<1].dis+tre[now<<1|1].dis; } int main() { scanf("%d%d",&n,&m); build(1,1,n); for(int i=1;i<=m;i++) { scanf("%d%d",&x,&y); Delete(1,x,y); printf("%d\n",tre[1].dis); } return 0; }
折花枝,恨花枝,准拟花开人共卮,开时人去时。
怕相思,已相思,轮到相思没处辞,眉间露一丝。