POJ 3321 Apple Tree(樹狀數組模板)

原題鏈接:POJ3321

解析:這題我按照郭煒老師的講義來練習樹狀數組的模板,但是也遇到了一些問題:

  1. 如果對一些圖或樹來用樹狀數組解題,就需要給他每個節點一個從1到nCount的編號,因爲樹狀數組只能從1~n求和
  2. 剛開始我用vector<int> G[maxn]來存圖,但是超時了,改用vector<vector<int> > G[maxn]就過了,可見以後儘量用第二種方法來存圖
  3. lowbit[]數組可以預處理,節約一點時間

代碼實例:

#include<iostream>
#include<cstdio>
#include<vector>
using namespace std;
const int maxn = 220000;
vector<vector<int> > G(maxn);//存邊 
int Start[maxn],End[maxn];//Start和End相當於存每個節點id 
int lowbit[maxn];//二進制最右面的1 
int C[maxn];//C[i]表示從A[i-lowbit[i]+1]到A[i] 的和,本題A[i]都爲1 
int nCount = 0;
int HasApple[maxn];//當前節點是否有蘋果 
void DFS(int v){
	Start[v] = ++nCount;
	for(int i = 0;i < G[v].size();i++)
		DFS(G[v][i]);
	End[v] = ++nCount;
}
int q_sum(int p){
	int nSum = 0;
	while(p > 0){
		nSum += C[p];//由於每段和都存在對應的C[i]中,故每次減去lowbit[i]來去下一段的C 
		p -= lowbit[p];
	}
	return nSum;
}
void Modify(int p,int val){
	while(p <= nCount){
		C[p] += val;
		p += lowbit[p];
	}
}
int main()
{
	int n;
	scanf("%d",&n);
	int u,v;
	for(int i = 0;i < n-1;i++){
		scanf("%d%d",&u,&v);
		G[u].push_back(v);
	}
	DFS(1);
	for(int i = 1;i <= nCount;i++)
		lowbit[i] = i&-i;
	for(int i = 1;i <= n;i++)
		HasApple[i] = 1;
	for(int i = 1;i <= nCount;i++)
		C[i] = i - (i - lowbit[i]);
	int m;
	scanf("%d",&m);
	for(int i = 0;i < m;i++){
		char cmd[10];
		int p;
		scanf("%s %d",cmd,&p);
		if(cmd[0] == 'C'){
			if(HasApple[p]){
				Modify(Start[p],-1);
				Modify(End[p],-1);
				HasApple[p] = 0;
			}else{
				Modify(Start[p],1);
				Modify(End[p],1);
				HasApple[p] = 1;
			}
		}else {	
			int t1 = q_sum(End[p]);
			int t2 = q_sum(Start[p]-1);
			printf("%d\n",(t1-t2)/2);//所求部分被計算了兩次 
		}
	}
	return 0;
} 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章