校门外的树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;
}