题意:给定n个区间,第i个区间的范围是[i-lowbit(i)+1,i]。一共有q组询问,询问有两种:
1 x y:询问sigma lowbit(i) (x<=i<=y)
2.x:询问有几个区间包含x这个下标
思路:先打一个lowbit的表找一下规律
考虑第一种询问,能将它拆成两个询问calc(x-1)和calc(y),其中calc(i)表示1到i中lowbit(i)的前缀和
枚举2的幂次,从高位到低位计数,每一个i都只在枚举到lowbit(i)时被算到
考虑第二种询问,树状数组中严格的区间包含(即父子关系)关系只在lowbit左移时出现,所以模拟树状数组更新时的操作,不断往上寻找父节点,计数即可
1 #include<cstdio> 2 #include<cstring> 3 #include<iostream> 4 #include<algorithm> 5 #include<cmath> 6 #include<bitset> 7 typedef long long ll; 8 using namespace std; 9 #define N 110000 10 #define oo 10000000 11 #define MOD 1000000007 12 13 14 ll lowbit(ll x) 15 { 16 return x&(-x); 17 } 18 19 ll calc(ll x) 20 { 21 ll ans=0; 22 ll y=1; 23 while((y<<1)<=x) y<<=1; 24 ll sum=0; 25 while(y) 26 { 27 ans+=y*(x/y-sum); 28 sum+=(x/y-sum); 29 y>>=1; 30 } 31 32 return ans; 33 } 34 35 int main() 36 { 37 ll n; 38 int q; 39 while(scanf("%I64d%d",&n,&q)!=EOF) 40 { 41 for(int i=1;i<=q;i++) 42 { 43 int op; 44 scanf("%d",&op); 45 if(op==1) 46 { 47 ll x,y; 48 scanf("%I64d%I64d",&x,&y); 49 ll ans=calc(y)-calc(x-1); 50 printf("%I64d ",ans); 51 } 52 else 53 { 54 ll x; 55 scanf("%I64d",&x); 56 ll ans=0; 57 while(x<=n) 58 { 59 ans++; 60 x+=lowbit(x); 61 } 62 printf("%I64d ",ans); 63 } 64 65 } 66 } 67 return 0; 68 } 69