校门外的树(线段树做法)

校门外马路上本来从编号0到L,每一编号的位置都有1棵树。有砍树者每次从编号A到B处连续砍掉每1棵树,就连树苗也不放过(记 0 A B ,含A和B);幸运的是还有植树者每次从编号C到D 中凡是空穴(树被砍且还没种上树苗或树苗又被砍掉)的地方都补种上树苗(记 1 C D,含C和D);问最终校门外留下的树苗多少棵?植树者种上又被砍掉的树苗有多少棵?

输入格式
第一行L和N,表示校园外原来有L+1棵树,并有N次砍树或种树的操作。

以下N行,砍树或植树的标记和范围,每行3个整数。

L(1 <= L <= 10000)和 N(1 <= N <= 100)

输出格式
共两行。第1行校门外留下的树苗数目,第2行种上又被拔掉的树苗数目。

输入输出样例
输入 #1复制
10 3
0 2 6
1 1 8
0 5 7
输出 #1复制
3
2

解题报告:这道题由于数据量小可以暴力做,但是为了训练,学点线段树的懒标记也好,在学长的帮助我才完成了这道题,维护三个信息,一个是种子数量,一个是树的数量,一个是懒标记。要注意的是下放懒标记的时候,他的儿子节点可能也会有懒标记,当他的懒标记是cut的时候要让它也要pushdown,所以要多开两倍空间。同时开一个cnt来记录删去的树种子值,他不是状态量是全局量所以可以写外面。

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<map>
#include<vector>
#include<queue>
#include<set>
#define IL inline
#define x first
#define y second
typedef long long ll;
using namespace std;
const	int N=10010;
struct node{
	int l;
	int r;
	int sum;
	int seed;
	int lazy;
}tr[N*8];
int cut;
void pushup(int u)
{
	tr[u].seed=tr[u<<1].seed+tr[u<<1|1].seed;
	tr[u].sum=tr[u<<1].sum+tr[u<<1|1].sum;
}
void pushdown(int	u)
{
	if(tr[u].lazy)
	{
	if(tr[u].lazy==1)
	{
		tr[u<<1].seed=tr[u<<1].r-tr[u<<1].l+1-tr[u<<1].sum;
		tr[u<<1|1].seed=tr[u<<1|1].r-tr[u<<1|1].l+1-tr[u<<1|1].sum;
		if(tr[u<<1].lazy==-1)
		pushdown(u<<1);
		if(tr[u<<1|1].lazy==-1)
		pushdown(u<<1|1);
	}
	else	if(tr[u].lazy==-1)
	{
		tr[u<<1].seed=0;
		tr[u<<1|1].seed=0;
		tr[u<<1].sum=0;
		tr[u<<1|1].sum=0;
	}
	tr[u<<1].lazy=tr[u].lazy;
	tr[u<<1|1].lazy=tr[u].lazy;
	tr[u].lazy=0;
		}
}
void build(int u,int l,int r)
{
	if(l==r)
	{
		tr[u]={l,r,1,0,0};
		return;
	}
	else
	{
		tr[u]={l,r,0,0,0};
		int mid=l+r>>1;
		build(u<<1,l,mid),build(u<<1|1,mid+1,r);
		pushup(u);
	}
}
void modify(int u,int l,int r,int d)
{
	if(tr[u].l>=l&&tr[u].r<=r)
	{
		if(d==1)
		{
			tr[u].seed=tr[u].r-tr[u].l+1-tr[u].sum;	
			if(tr[u].lazy==-1) pushdown(u);
			tr[u].lazy=1;	
		}
		else
		{
			cut+=tr[u].seed;
			tr[u].seed=0;
			tr[u].sum=0;
		//	if(tr[u].lazy==1)
		//	pushdown(u);
			tr[u].lazy=-1; 
		}
		return ;
	}
	else
	{
		pushdown(u);
		int mid=tr[u].l+tr[u].r>>1;
		if(l<=mid)	modify(u<<1,l,r,d);
		if(r>mid)	modify(u<<1|1,l,r,d);
		pushup(u);
	}
}
int main()
{
	int n;
	int m;
	cin>>n>>m;
	build(1,0,n);
	while(m--)
	{
		int op,l,r;
		cin>>op>>l>>r;
		if(op==1)
		{
			modify(1,l,r,1);
		}
		else
		{
			modify(1,l,r,-1);
		}
	}
	cout<<tr[1].seed<<endl;
	cout<<cut<<endl;
    return 0;
}



全部评论

相关推荐

10-05 11:11
海南大学 Java
投票
理想江南137:感觉挺真诚的 感觉可以试一试
点赞 评论 收藏
分享
评论
点赞
2
分享
牛客网
牛客企业服务