校门外的树2 contest 树状数组练习 T4

Description

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


Input

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


Output

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


Hint

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


Solution

用两个区间的树状数组分别维护起点数量和终点数量。那么查询的时候ans就等于r前面的起点数量减去l-1前面的终点数量。因为l-1前面就已经终点了的话,这种树就不包含在查询的这个区间里面。

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define maxn 50005
#define lowbit(x) (x&(-x))
#define int long long
using namespace std;
int c1[maxn],c2[maxn],c3[maxn],c4[maxn];
int n,m,x,y,z;
void doAdd(int x,int dd){
	int f=x;
	while(x<=n){
		c1[x]+=f*dd;
		c3[x]+=dd;
		x+=lowbit(x);
	}
}
void doadd(int x,int dd){
	int f=x;
	while(x<=n){
		c2[x]+=f*dd;
		c4[x]+=dd;
		x+=lowbit(x);
	}
}
int doFinD(int x){
	int f=x,ans=0;
	while(x>0){
		ans+=(f+1)*c3[x]-c1[x];
		x-=lowbit(x);
	}
	return ans;
}
int dofinD(int x){
	int f=x,ans=0;
	while(x>0){
		ans+=(f+1)*c4[x]-c2[x];
		x-=lowbit(x);
	}
	return ans;
}
signed main(){
	scanf("%lld%lld",&n,&m);
	for(int i=1;i<=m;i++){
		scanf("%lld",&x);
		if(x==1){
			scanf("%lld%lld",&y,&z);
			doAdd(y,1);
			doAdd(y+1,-1);
			doadd(z,1);
			doadd(z+1,-1); 
		}
		else if(x==2){
			scanf("%lld%lld",&y,&z);
			printf("%lld\n",doFinD(z)-dofinD(y-1));
		}
	}
	return 0;
}
posted @ 2018-11-30 17:23  虚拟北方virtual_north。  阅读(169)  评论(0编辑  收藏  举报