校门外的树
https://loj.ac/problem/10115
题目描述
有一条路,每次有两种操作,一是在\([l,r]\)间种上树,每次种的树的种类不同,二是询问区间\([l,r]\)中有多少种树。
思路
我们考虑对于每次种树,有效的区间信息可以由开头和结尾得到,所以如果我们要求\([l,r]\)之间的树的种类数,我们用\(a[i]\)表示\(i\)之前(包括\(i\))有多少个区间开头,我们用\(b[i]\)表示\(i\)之前(包括\(i\))有多少个区间结尾,那么对于询问区间\([l,r]\)答案就是在\(l\)之前的开头数-\(r\)之前的结尾数,用树状数组维护这个信息即可。
代码
#include <bits/stdc++.h>
using namespace std;
const int N=5e4+10;
int read()
{
int res=0,w=1;
char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){res=(res<<3)+(res<<1)+ch-'0';ch=getchar();}
return res*w;
}
int a[N],b[N],n;
int lowbit(int x)
{
return x&-x;
}
void add(int c[],int x,int w)
{
while(x<=n)
{
c[x]+=w;
x+=lowbit(x);
}
}
int query(int c[],int x)
{
int res=0;
while(x)
{
res+=c[x];
x-=lowbit(x);
}
return res;
}
int main()
{
int m;
n=read();m=read();
while(m--)
{
int k=read(),l=read(),r=read();
if(k==1)
{
add(a,l,1);
add(b,r,1);
}
else
printf("%d\n",query(a,r)-query(b,l-1));
}
}