校门外的树
传送门
又是一道树状数组经典题目
分析:
首先这道题,你有可能想到的是区间打标记,似乎跟树状数组扯不到一点关系。但我们需要建模。题目说在 [ l , r ] [l,r] [l,r]这个区间里种植一棵树,那么可以这样理解:就是在 l , r l,r l,r这两个点上打上一个标记。怎样体现是这个区间呢?我们就用一对(),当然你用0和1也行。
打上标记后,我们来看:
r
r
r左边(前边)的左括号
(
(
( 代表从开头到
r
r
r的树种类数;
l
l
l左边的右括号
)
)
) 代表从开头到
l
l
l种了多少棵树。
具体情况见下图:
我们可以发现
l
l
l左边的右括号所对应的左括号也一定是在区间之外的,我们是要将这部分树给去掉的。而这些左括号的个数就是等于
l
l
l左边右括号的个数。所以最后我们要这样求:
r
左
边
左
括
号
的
个
数
−
l
左
边
右
括
号
的
个
数
r左边左括号的个数-l左边右括号的个数
r左边左括号的个数−l左边右括号的个数
怎么样?是不是跟树状数组很相似?
前面的打标记就是单点修改,后面就是前缀和之差。
代码:
#include <bits/stdc++.h>
using namespace std;
const int maxv=50010;
int t1[maxv],t2[maxv];
int n,m;
int lowbit(int x)
{
return x&(-x);
}
void update1(int x,int y)//'('
{
while(x<=n)
{
t1[x]+=y;
x+=lowbit(x);
}
}
void update2(int x,int y)//')'
{
while(x<=n)
{
t2[x]+=y;
x+=lowbit(x);
}
}
int sum1(int x)//'('
{
int s=0;
while(x>0)
{
s+=t1[x];
x-=lowbit(x);
}
return s;
}
int sum2(int x)//')'
{
int s=0;
while(x>0)
{
s+=t2[x];
x-=lowbit(x);
}
return s;
}
int main()
{
cin>>n>>m;
while(m--)
{
int k,l,r;
cin>>k>>l>>r;
if(k==1)
{
update1(l,1);//l打( 左括号
update2(r,1);//r打) 右括号
}
else cout<<sum1(r)-sum2(l-1)<<endl;
}
return 0;
}