***********(北大)树状数组*************

目录

树状数组入门:

POJ 3321 Apple Tree

NYOJ 123 士兵杀敌(四)

POJ 2299 Ultra-QuickSort 



树状数组入门:

见博客

POJ 3321 Apple Tree

Description

There is an apple tree outside of kaka's house. Every autumn, a lot of apples will grow in the tree. Kaka likes apple very much, so he has been carefully nurturing the big apple tree.

The tree has N forks which are connected by branches. Kaka numbers the forks by 1 to N and the root is always numbered by 1. Apples will grow on the forks and two apple won't grow on the same fork. kaka wants to know how many apples are there in a sub-tree, for his study of the produce ability of the apple tree.

The trouble is that a new apple may grow on an empty fork some time and kaka may pick an apple from the tree for his dessert. Can you help kaka?

 

 

Input

The first line contains an integer N (N ≤ 100,000) , which is the number of the forks in the tree.
The following N - 1 lines each contain two integers u and v, which means fork u and fork v are connected by a branch.
The next line contains an integer M (M ≤ 100,000).
The following M lines each contain a message which is either
"x" which means the existence of the apple on fork x has been changed. i.e. if there is an apple on the fork, then Kaka pick it; otherwise a new apple has grown on the empty fork.
or
"x" which means an inquiry for the number of apples in the sub-tree above the fork x, including the apple (if exists) on the fork x
Note the tree is full of apples at the beginning

Output

For every inquiry, output the correspond answer per line.

Sample Input

3
1 2
1 3
3
Q 1
C 2
Q 1

Sample Output

3
2

Source

POJ Monthly--2007.08.05, Huang, Jinsong

 

#include<stdio.h>
#include<stdlib.h>
#include<iostream>
#include<algorithm>
#include<vector>
using namespace std;
const int maxn=220000;
int c[maxn];
int start[maxn];
int end[maxn];
int lowbit[maxn];
int hasApple[maxn/2];
int cnt=0;
typedef vector<int> VCT_INT;
vector<VCT_INT>G(maxn/2); //注意 二维数组 
void dfs(int v)
{
	start[v]=++cnt;
	for(int i=0;i<G[v].size();i++)
	 dfs(G[v][i]);
	end[v]=++cnt;
}
int getSum(int p)
{
	int ans=0;
 	 while(p>0)
    {
     ans+=c[p];
     p-=lowbit[p];
	}
	/*for(int i=p;i>0;i-=lowbit[i])
	  ans+=c[i];*/
	return ans;
}
void modfiy(int p,int value)
{
	while(p<=cnt)
	{
	//	printf(" c[%d]= %d ",p,c[p]);
		c[p]+=value;
	//	printf(" c[%d]= %d ",p,c[p]);
		p+=lowbit[p];
	//	printf(" c[%d]= %d ",p,c[p]);
	}
}
int main()
{
	int n,m,a,b;
	scanf("%d",&n);
	for(int i=0;i<n-1;i++)
	{
		scanf("%d%d",&a,&b);
		G[a].push_back(b);
	}
	cnt=0;
	dfs(1);
	for(int i=1;i<=cnt;i++)
	{
		 lowbit[i]=i&(i^(i-1));
	//	 printf("lowbit[%d] = %d\n",i,lowbit[i]);
	}
	for(int i=1;i<=n;i++)
	  hasApple[i]=1;
	  
	  for(int i=1;i<=cnt;i++)
	  {
	    c[i]=i-(i-lowbit[i]);
	//	printf("c[%d] = %d ",i,c[i]);
	  }

	    
	scanf("%d",&m);
	for(int i=0;i<m;i++)
	{
		char s[20];
    	int t;
		scanf("%s%d",s,&t);
		if(s[0]=='C')
		{
			if(hasApple[t])
			{
				modfiy(start[t],-1);
			//	cout<<endl;
				modfiy(end[t],-1);
			//	cout<<endl;
				hasApple[t]=0;
			}
			else
			{
				modfiy(start[t],1);
			//	cout<<endl;
				modfiy(end[t],1);
			//	cout<<endl;
				hasApple[t]=1;
			}
		}
		else
		{
			int p1=getSum(end[t]);
			int p2=getSum(start[t]-1);
			printf("%d\n",(p1-p2)/2);
		}
	}
	return 0;
}

NYOJ 123 士兵杀敌(四)

 

描述

南将军麾下有百万精兵,现已知共有M个士兵,编号为1~M,每次有任务的时候,总会有一批编号连在一起人请战(编号相近的人经常在一块,相互之间比较熟悉),最终他们获得的军功,也将会平分到每个人身上,这样,有时候,计算他们中的哪一个人到底有多少军功就是一个比较困难的事情,军师小工的任务就是在南将军询问他某个人的军功的时候,快速的报出此人的军功,请你编写一个程序来帮助小工吧。

假设起始时所有人的军功都是0.

输入

只有一组测试数据。
每一行是两个整数T和M表示共有T条指令,M个士兵。(1<=T,M<=1000000)
随后的T行,每行是一个指令。
指令分为两种:
一种形如
ADD 100 500 55 表示,第100个人到第500个人请战,最终每人平均获得了55军功,每次每人获得的军功数不会超过100,不会低于-100。
第二种形如:
QUERY 300 表示南将军在询问第300个人的军功是多少。

输出

对于每次查询输出此人的军功,每个查询的输出占一行。

样例输入

4 10
ADD 1 3 10
QUERY 3
ADD 2 6 50
QUERY 3

样例输出

10
60

来源

[张云聪]原创

上传者 

张云聪

简述代码用树状数组的思路解题过程:参考上图,更易理解

1.c数组起初全部是0,这一点必须要提前明确。

2.举例:ADD 1 3 10 ,从第1个人到第3个人每个人都加10,首先,c(1)是要加10,因为c(1)=a1,然后1的二进制数要往左移一位;a=2,c(2)要加10,因为c(2)=a1+a2,然后2的二进制数要往左移一位;a=4,c(4)要加10,因为c(4)=a1+a2+a3+a4,然后4的二进制数要往左移一位;a=8,c(8)=10,c(8)=a1+a2+a3+a4+a5+a6+a7+a8;之后由于控制条件的约束,就不在继续。

但是上述过程把1到N都加了一遍,我们要的是1到3,所以要把3之后的加上的军功减掉,因此还要再调用一次update函数,来把3之后的军功减掉之后才是我们要加的军功。

3.举例:QUERY 3,求第3个人的军功,sum+=c(3),c(3)为0,还没有加过军功,然后要往左走,就到了c(2),c(2)的军功刚刚加了是10,所以,a3的军功就是10了。

4.当a数组中某一个数变动的时候。与a数组元素有关的c数组也要更新。

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<iostream>
#include<algorithm>
#include<queue>
#include<math.h>
using namespace std;
int c[1010000],N;
int lowbit(int p) //lowbit(p) 实际上就是p的二进制表示形式留下最右边的1,其他位都变成0
{
//	printf("p&(-p) = %d \n",p&(-p));
	return p&(-p);
}
int getSum(int x) //前x个数和 
{
	int sum=0;
	while(x>0)
	{
	//	printf("x = %d \n",x);
		sum+=c[x];
	//	printf("sum = %d \n",sum) ;
		x-=lowbit(x);
	}
	return sum;
}
void update(int a,int b)
{
	while(a<=N)
	{
		//printf("a = %d \n",a);
		c[a]+=b;
		a+=lowbit(a);
	}
}
int main()
{
	int T;
	scanf("%d%d",&T,&N);
	while(T--)
	{
		char s[20];
		scanf("%s",s);
		if(s[0]=='A')
		{
			int l,r,num;
			scanf("%d%d%d",&l,&r,&num);
			update(l,num);//l到N的数字都加num 
			update(r+1,-num);//因为我们要在l到r这个区间加上num,所以要把r+1到N的数字都减去刚刚加上的num 
		}
		else
		{
			int x;
			scanf("%d",&x);
			printf("%d\n",getSum(x));
		}
	}
	return 0;
}

注意:

1.    update(l,num);//l到N的数字都加num 
            update(r+1,-num);//因为我们要在l到r这个区间加上num,所以要把r+1到N的数字都减去刚刚加上的num 

        

POJ 2299 Ultra-QuickSort 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值