openjudge 校门外的树3

来源:互联网 发布:金蝶k3无法数据引出 编辑:程序博客网 时间:2024/06/05 10:05
P1473 校门外的树3
时间: 1000ms / 空间: 131072KiB / Java类名: Main

描述

 校门外有很多树,有苹果树,香蕉树,有会扔石头的,有可以吃掉补充体力的……
如今学校决定在某个时刻在某一段种上一种树,保证任一时刻不会出现两段相同种类的树,现有两个操作:
K=1,读入l,r表示在l~r之间种上的一种树
K=2,读入l,r表示询问l~r之间能见到多少种树
(l,r>0)

输入格式

第一行n,m表示道路总长为n,共有m个操作
接下来m行为m个操作

输出格式

对于每个k=2输出一个答案

测试样例1

输入

5 4 
1 1 3 
2 2 5 
1 2 4 
2 3 5

输出


2

备注

范围: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;
}
0 0
原创粉丝点击