题目链接:P1276 校门外的树(增强版) - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
好久没做线段树了,快要打济南区域赛了,来复习一下线段树*+*
题目是中文的,我在这就不说明题意了,注意,题目中问的问题:留下的树苗有多少颗,树苗是树被砍掉后种下的,所以在这我们要开两个线段树,一个用来存储原来的树的状态,另一个要存储树和树苗共存的形态,我们记录每次操作真实种植的树以及真实砍掉的树,什么叫真实种植的树呢?比如我们要对区间【l,r】种树,在这个区间种已经有了x棵树,那我们的真实种树量就应该是r-l+1-x棵,真实砍掉的树的计算方法同理。
先来看一下怎么求最终校门外留下的树苗的数目吧,最终校门外的树以及树苗数我们可以直接通过第二棵线段树一次查询直接求出,而最终校门外的树的数目我们可以直接通过第一棵线段树一次查询直接求出,这样两者作差就得到了这个问题的答案
现在我们来看一下怎么求出植树者种上又被砍掉的树苗有多少棵,过程中一共砍掉的树及树苗数我们已经在之前记录下来了,而我们在第一颗线段树种又可以通过一次查询直接求出当前剩余的树的数目,我们用一开始的树的数目减去最后剩余的树的数目就得到了在过程中砍掉的树的数目,这时候我们就可以用之前保存的砍掉的树及树苗的个数减去过程中砍掉的树的数目就得到了被砍掉的树苗的个数。
下面是代码:
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<queue>
using namespace std;
const int N=5e5+10;
int sum[2][N],l[2][N],r[2][N],lazy[2][N];
void pushup(int k,int id)
{
sum[k][id]=sum[k][id<<1]+sum[k][id<<1|1];
}
void pushdown(int k,int id)
{
if(lazy[k][id]!=-1)
{
lazy[k][id<<1]=lazy[k][id];
lazy[k][id<<1|1]=lazy[k][id];
sum[k][id<<1]=(r[k][id<<1]-l[k][id<<1]+1)*lazy[k][id];
sum[k][id<<1|1]=(r[k][id<<1|1]-l[k][id<<1|1]+1)*lazy[k][id];
lazy[k][id]=-1;
}
}
void build(int k,int id,int L,int R)
{
l[k][id]=L;r[k][id]=R;sum[k][id]=0;lazy[k][id]=-1;
if(L==R)
{
sum[k][id]=1;
return ;
}
int mid=L+R>>1;
build(k,id<<1,L,mid);
build(k,id<<1|1,mid+1,R);
pushup(k,id);
}
void update_interval(int k,int id,int L,int R,int val)
{
if(l[k][id]>=L&&r[k][id]<=R)
{
sum[k][id]=(r[k][id]-l[k][id]+1)*val;
lazy[k][id]=val;
return ;
}
pushdown(k,id);
int mid=l[k][id]+r[k][id]>>1;
if(L<=mid) update_interval(k,id<<1,L,R,val);
if(mid+1<=R) update_interval(k,id<<1|1,L,R,val);
pushup(k,id);
}
int query_interval(int k,int id,int L,int R)
{
if(L<=l[k][id]&&r[k][id]<=R) return sum[k][id];
pushdown(k,id);
int mid=l[k][id]+r[k][id]>>1;
int ans=0;
if(mid>=L) ans+=query_interval(k,id<<1,L,R);
if(mid+1<=R) ans+=query_interval(k,id<<1|1,L,R);
return ans;
}
int main()
{
int l,n;
cin>>l>>n;
build(0,1,0,l);
build(1,1,0,l);
int ans1=0;//记录原始马路上的树被砍掉的数量
int ans2=0;//记录实际植树的数量
for(int i=1;i<=n;i++)
{
int ll,rr,op;
scanf("%d%d%d",&op,&ll,&rr);
if(op==0)
{
ans1+=query_interval(0,1,ll,rr);//记录原始马路上的树中有多少棵被砍掉
update_interval(0,1,ll,rr,0);
update_interval(1,1,ll,rr,0);
}
else
{
ans2+=rr-ll+1-query_interval(1,1,ll,rr);
update_interval(1,1,ll,rr,1);
}
}
printf("%d\n%d",query_interval(1,1,0,l)-query_interval(0,1,0,l),l+1+ans2-ans1-query_interval(1,1,0,l));
return 0;
}
本文通过一道编程题《校门外的树(增强版)》详细介绍了如何使用两棵线段树来解决区间更新和查询的问题,并给出了完整的代码实现。
 (线段树)&spm=1001.2101.3001.5002&articleId=121126874&d=1&t=3&u=99e263059f3a41d9a969a3b196dca122)
864

被折叠的 条评论
为什么被折叠?



