树状数组原理题。
题目大意实际上是问,从1-n建立一个树状数组,
1.第一个询问就是求从L到R的lowbit(i)之和,这个我们可以转换为求1-R的lowbit(i)之和,类似求前缀和。
那么1-R的lowbit(i)怎么求呢。如果写出1-16的lowbit值就可以发现实际上lowbit(i)是有很强的规律的:根据lowbit的定义,转化成10进制实际上就是,对于一个数i,含有的最大的2的次方的因子就是Lowbit(i)的值。举个例子,16含有最大的因子是2^4,所以lowbit值是2^4即16本身,24含有的最大因子是2^3,所以lowbit(24)=2^3=8,,有了这个规律以后我们就可以用logN的时间算出1-N的lowbit之和。
2.第二个询问实际上是问,x在树状数组中被多少个节点管辖,这个只要一直往上找父亲节点,统计数量就行了。
补充:如果i-lowbit(i)=j,那么j+lowbit(j)=i.
#include <cstdio>
#include <algorithm>
#include <cmath>
using namespace std;
#define ll long long
#define lowbit(x) ((x)&(-x))
ll n,l,r,x;
int t,q;
ll find(ll x){
ll ret=0;
for (;x<=n;x+=lowbit(x),ret++);
return ret;
}
ll calc(ll n){
ll ret=0;
for (ll p=1;p<=n;p<<=1)
ret+=(n/p-n/(p<<1))*p;
return ret;
}
int main(){
while (~scanf("%I64d %d",&n,&q)){
while (q--){
scanf("%d",&t);
if (t==1){
scanf("%I64d %I64d",&l,&r);
printf("%I64d\n",calc(r)-calc(l-1));
}
else{
scanf("%I64d",&x);
printf("%I64d\n",find(x));
}
}
}
return 0;
}