1. 程式人生 > >hdu—5976—Aninteresting game(樹狀陣列原理+特徵)

hdu—5976—Aninteresting game(樹狀陣列原理+特徵)

Aninteresting game

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) Total Submission(s): 886    Accepted Submission(s): 341  

Problem Description

Let’s play a game.We add numbers 1,2...n in increasing order from 1 and put them into some sets. When we add i,we must create a new set, and put iinto it.And meanwhile we have to bring [i-lowbit(i)+1,i-1] from their original sets, and put them into the new set,too.When we put one integer into a set,it costs us one unit physical strength. But bringing integer from old set does not cost any physical strength. After we add 1,2...n,we have q queries now.There are two different kinds of query: 1 L R:query the cost of strength after we add all of [L,R](1≤L≤R≤n) 2 x:query the units of strength we cost for putting x(1≤x≤n) into some sets.

Input

There are several cases,process till end of the input. For each case,the first line contains two integers n and q.Then q lines follow.Each line contains one query.The form of query has been shown above. n≤10^18,q≤10^5

Output

For each query, please output one line containing your answer for this query

Sample Input

10 2 1 8 9 2 6

Sample Output

9 2

Hint

lowbit(i) =i&(-i).It means the size of the lowest nonzero bits in binary of i. For example, 610=1102, lowbit(6) =102= 210 When we add 8,we should bring [1,7] and 8 into new set. When we add 9,we should bring [9,8] (empty) and 9 into new set. So the first answer is 8+1=9. When we add 6 and 8,we should put 6 into new sets. So the second answer is 2.

Source

Recommend

wange2014   |   We have carefully selected several similar problems for you:  6447 6446 6445 6444 6443 

因為插入i的貢獻是[i-lowbit(i)+1,i-1] 的長度,所以i的貢獻就是(i-1)-(i-lowbit(i)+1),就是lowbit(i)

所以這個題目化簡成了:

①:求【L,R】的lowbit(i)的和

②:數字x在幾個集合裡面

思想:

第二種比較好算,要找到x在幾個集合中,可用x=x+lowbit(x)找出有多少滿足條件的x,就能得到集合的個數。

第一種需要推一下公式

可以發現lowbit的值肯定是1,2,4,8,16.。。。2的n次方。所以利用容斥原理,假如我想知道2的個數,那麼就用n/2算出有幾個可以整除2,減掉可以整除2*2的個數。嗯。

我們可以發現,每k個 k ∈{1,2,4,8……}會出現1個k的倍數,所以我們能夠知道[1,i]中有多少個不同的k以及每個k的個數p(類似於容斥原理)。所以能夠求得[1,i]的長度和是多少,進而求得[a,b]的長度和。

程式碼:

#include<stdio.h>
typedef long long ll;
ll tmp[65],n,m;
ll findans(ll x)
{
	ll ans=0;
	for(ll i=0;tmp[i]<=x;i++)
		ans+=(x/tmp[i]-x/tmp[i+1])*tmp[i];
	return ans;
}
int main(void)
{
	int i;
	tmp[0]=1;
	for(i=1;i<=63;i++)
		tmp[i]=tmp[i-1]*2;
	while(scanf("%lld%lld",&n,&m)!=EOF)
	{
		ll x,y,t;
		while(m--)
		{
			scanf("%lld",&t);
			if(t==1)
			{
				scanf("%lld%lld",&x,&y);
				printf("%lld\n",findans(y)-findans(x-1));
			}
			else
			{
				ll ans=0;
				scanf("%lld",&x);
				while(x<=n)
				{
					ans++;
					x+=x&(-x);
				}
				printf("%lld\n",ans);
			}
		}
	}
	return 0;
}