前言

本蒟蒻重学线段树,发现了这道题可以用线段树做。

虽然数据范围很小可以直接暴力,但由于在练习线段树所以打算用线段树写这道题。

本题解针对已经有线段树基础的巨佬,不懂线段树原理的话可以学习线段树后再阅读本题解。

审题

刚看题的时候以为大概是个线段树模板,结果发现事情并不简单。

题目要求的不是剩下多少棵树和砍掉了多少棵树木,而是要求剩下和砍掉了多少棵树苗

并且需要注意区间是从0开始的。

那么注意到这些差不多就可以开始想做法了。

解决

因为种树人每次种树种植的都是树苗,所以只有最初的区间上会有一整个区间的树木。所以我们可以对于树木建立一棵线段树,再对于树木和树苗共同建立一棵线段树。这样在砍树的时候分别查询两棵线段树并且进行差分,就可以得到区间上砍掉的树苗的数量。最后查询整个区间上树苗个数同理

其中线段树需要支持的操作

  • 区间赋值
  • 区间加查询

Code

那么具体实现代码如下:

#include<bits/stdc++.h>
using namespace std;
#define file(a) freopen(#a".in","r",stdin),freopen(#a".out","w",stdout)
#define LL long long
#define N 10010
int n,m;
struct node_tree
{
	int l,r,mid;
	int vol,d;//vol是赋值的lazy标记
};
struct tree//为了方便维护两棵线段树,于是开了结构体
{
	node_tree t[N*4];
	void build(int i,int l,int r)//建树,本质上是初始化
	{
		t[i].l=l;t[i].r=r;t[i].mid=(l+r)>>1;
		t[i].d=0;t[i].vol=-1;
		if(l==r)
		{
			t[i].d=0;;
			return;
		}
		build(i<<1,l,t[i].mid);
		build(i<<1|1,t[i].mid+1,r);
		t[i].d=(t[i<<1].d+t[i<<1|1].d);
		return;
	}
	void pushdown(int i)
	{
		if(!(~t[i].vol)) return;
		//这里是防止赋值上初始化值,因为(~(-1))==0
		t[i<<1].vol=t[i].vol;
		t[i<<1|1].vol=t[i].vol;
		
		t[i<<1].d=t[i].vol*(t[i<<1].r-t[i<<1].l+1);
		t[i<<1|1].d=t[i].vol*(t[i<<1|1].r-t[i<<1|1].l+1);
		
		t[i].vol=-1;
		return;
	}
	void modify_vol(int i,int l,int r,int k)//区间赋值
	{
		if(l<=t[i].l&&t[i].r<=r)
		{
			t[i].d=k*(t[i].r-t[i].l+1);
			t[i].vol=k;
			return;
		}
		pushdown(i);
		if(l<=t[i].mid) modify_vol(i<<1,l,r,k);
		if(t[i].mid+1<=r) modify_vol(i<<1|1,l,r,k);
		t[i].d=(t[i<<1].d+t[i<<1|1].d);
		return;
	}
	int query(int i,int l,int r)//查询区间和
	{
		if(l<=t[i].l&&t[i].r<=r)
		{
			return t[i].d;
		}
		pushdown(i);
		int res=0;
		if(l<=t[i].mid) res+=query(i<<1,l,r);
		if(t[i].mid+1<=r) res+=query(i<<1|1,l,r);
		return res;
	} 
}t1,t2;//t1存树木 t2存树苗加树木
int ans1,ans2;
int main()
{
	scanf("%d%d",&n,&m);
	t1.build(1,0,n);t2.build(1,0,n);
	t1.modify_vol(1,0,n,1);t2.modify_vol(1,0,n,1);//初始化
	while(m--)
	{
		int opt,l,r;
		scanf("%d%d%d",&opt,&l,&r);
		if(!opt)
		{
			ans2+=t2.query(1,l,r)-t1.query(1,l,r);
			t1.modify_vol(1,l,r,0);
			t2.modify_vol(1,l,r,0);
		}
		if(opt)
		{
			t2.modify_vol(1,l,r,1);
		}
		/*
		这个是线段树调试(可以忽略)
		for(int i=0;i<=n;++i)
		{
			printf("%d(%d)[%d] ",t2.query(1,i,i),t1.query(1,i,i),i);
		}
		putchar('\n');
		*/
	}
	ans1=t2.query(1,0,n)-t1.query(1,0,n);
	printf("%d\n%d",ans1,ans2);
	return 0;
}