描述
校门外有很多树,有苹果树,香蕉树,有会扔石头的,有可以吃掉补充体力的……
如今学校决定在某个时刻在某一段种上一种树,保证任一时刻不会出现两段相同种类的树,现有两个操作:
K=1,读入l,r表示在l~r之间种上的一种树
K=2,读入l,r表示询问l~r之间能见到多少种树
(l,r>0)
输入格式
第一行n,m表示道路总长为n,共有m个操作
接下来m行为m个操作
备注
范围:20%的数据保证,n,m<=100
60%的数据保证,n <=1000,m<=50000
100%的数据保证,n,m<=50000
注意:树是可以重叠的,比如1号位置上可以种多种树
此题是一道不错的线段树题,做题前一定要想清楚,如果一个区间的左右子树都含有同一种树,那么对于这个区间绝不是1+1=2,而还应该是1,所以我们需要一个数组去记录左右子树相同树的个数。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
int a[2000000],i,j,n,m,p[2000000],s[2000000];
void pushdown(int now,int l,int r,int mid)
{
if (s[now]!=0)//下放时一定要想明白,既然可以下放则说明他的左右子树有,需要更新p数组
{
s[now<<1]+=s[now];
s[(now<<1)+1]+=s[now];
a[now<<1]+=s[now];
a[(now<<1)+1]+=s[now];
p[now<<1]+=s[now];
p[(now<<1)+1]+=s[now];
s[now]=0;
}
}
void qchange(int now,int l,int r,int ll,int rr)
{
if (l>=ll&&rr>=r)
{
s[now]+=1;
a[now]++;
p[now]++;
return ;
}
int mid=(l+r)/2;
pushdown(now,l,r,mid);
a[now]++;
int pd1=0,pd2=0;
if (ll<=mid)
{
qchange(now<<1,l,mid,ll,rr);
pd1=1;
}
if (rr>mid)
{
qchange((now<<1)+1,mid+1,r,ll,rr);
pd2=1;
}
if (pd1==1&&pd2==1)
p[now]++;
}
int qsum(int now,int l,int r,int ll,int rr)
{
int mid=(l+r)/2;
pushdown(now,l,r,mid);
if (ll<=l&&rr>=r)
{
return a[now];
}
int ans=0;
int pd1=0,pd2=0;
if (ll<=mid)
ans+=qsum(now<<1,l,mid,ll,rr),pd1=1;
if (rr>mid)
ans+=qsum((now<<1)+1,mid+1,r,ll,rr),pd2=1;
if (pd1==1&&pd2==1)
return ans-p[now];
else
return ans;
}
int main()
{
//freopen("a.in","r",stdin);
scanf("%d%d",&n,&m);
for (i=1;i<=m;i++)
{
int x,y,z;
scanf("%d%d%d",&x,&y,&z);
if (x==1)
{
qchange(1,1,n,y,z);
}
else
{
printf("%d\n",qsum(1,1,n,y,z));
}
}
return 0;
}