校门外的树

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));
	}
}

posted @ 2019-10-28 20:12  fbz  阅读(78)  评论(0编辑  收藏  举报