[树状数组]校门外的树

校 门 外 的 树 校门外的树


题目描述

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


输入

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


输出

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


样例输入

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


样例输出

1
2


数据范围

20 20 20%的数据保证, n , m < = 100 n,m<=100 n,m<=100
60 60 60%的数据保证, n < = 1000 , m < = 50000 n <=1000,m<=50000 n<=1000,m<=50000
100 100 100%的数据保证, n , m < = 50000 n,m<=50000 n,m<=50000


题目解析

首先看题,不难看出是区间修改和区间查询。
可以用线段树树状数组来实现代码
但因为数据规模较大,所以我们选择了时间复杂度较小的树状数组

在程序中的lowbit函数, − x -x x 的值,其实就是在x的值的基础上进行按位取反 (~ x x x)之后在增加1所得,也是运用到一个二进制优化。

x & (-x) = x & (~x + 1)

那么如果 x x x 是一个偶数,那么就可以得出

  • x x x & ( − x ) (-x) (x) = 2 2 2x

那么如果 x x x是一个奇数,那么就可以得出

  • x x x & ( − x ) (-x) (x) = 1 1 1

不信?那么可以自己推一下(


code

#include<stdio.h>
#include<iostream> 
#include<algorithm>
using namespace std;
int n,m,a[50005],b[50005]; 
int lowbit(int x)
{
	return x & (-x);
}
void add1(int x,int k)
{
	for(int i=x;i<=n;i+=lowbit(i))
	 b[i]+=k;
}
void add2(int x,int k)
{
	for(int i=x;i<=n;i+=lowbit(i))
	 a[i]+=k;
}
int sum1(int x)
{
	int sum=0;
	for(int i=x;i;i-=lowbit(i))sum+=a[i];
	return sum;
}
int sum2(int x)
{
	int sum=0;
	for(int i=x;i;i-=lowbit(i))sum+=b[i];
	return sum;
}
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;++i)
    {
    	int k,l,r;
		scanf("%d%d%d",&k,&l,&r);
		if(l>r)
		 swap(l,r);
		if(k==1)
		{
			add1(r,1);
			add2(l,1);		
		}	
		else 
		{	
			printf("%d\n",sum1(r)-sum2(l-1));
		}
    }
    return 0;
}


posted @ 2020-08-18 15:01  unknown_future  阅读(115)  评论(0编辑  收藏  举报