关于树状数组:参看:[url]http://128kj.iteye.com/blog/1743633[/url]
POJ3321 题意:
一棵具有n个节点的树,一开始,每个节点上都有一个苹果。现在给出m组动态的操作:
(C,i)是摘掉第i个节点上面的苹果(若苹果不存在,则为加上一个苹果),(Q,i)是查询以第i个节点为根的子树有几个苹果(包括第i个节点)。
输入是叉之间的关系,
1 2
1 3
就是主干上面两个叉分别是2 和3.
[img]http://dl.iteye.com/upload/attachment/0077/7432/7482a5a4-8a0d-34fb-bb92-abc3c6f2d1e1.gif[/img]
样例:
Sample Input
3
1 2
1 3
3
Q 1
C 2
Q 1
Sample Output
3
2
分析:
用树状数组求和,这个数组怎么来定?
从root开始dfs下去记录第一次访问u点时的时间戳为Begin[u](下标),当访问完以u为根的所有子树以后要向上回溯的时候,再记录一个时间戳End[u](下标),这样,这棵树上子树u上的所有苹果和就是Begin[u]到End[u]的区间和,操作就和普通的树状数组一样了~
下面是AC过的代码:
源码:
POJ3321 题意:
一棵具有n个节点的树,一开始,每个节点上都有一个苹果。现在给出m组动态的操作:
(C,i)是摘掉第i个节点上面的苹果(若苹果不存在,则为加上一个苹果),(Q,i)是查询以第i个节点为根的子树有几个苹果(包括第i个节点)。
输入是叉之间的关系,
1 2
1 3
就是主干上面两个叉分别是2 和3.
[img]http://dl.iteye.com/upload/attachment/0077/7432/7482a5a4-8a0d-34fb-bb92-abc3c6f2d1e1.gif[/img]
样例:
Sample Input
3
1 2
1 3
3
Q 1
C 2
Q 1
Sample Output
3
2
分析:
用树状数组求和,这个数组怎么来定?
从root开始dfs下去记录第一次访问u点时的时间戳为Begin[u](下标),当访问完以u为根的所有子树以后要向上回溯的时候,再记录一个时间戳End[u](下标),这样,这棵树上子树u上的所有苹果和就是Begin[u]到End[u]的区间和,操作就和普通的树状数组一样了~
下面是AC过的代码:
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.StreamTokenizer;
import java.util.*;
public class Main{
//把苹果树作图处理了。
private List<ArrayList<Integer>> G;// 邻接表。注:使用邻接矩阵内存溢出。
private int k;//顶点数目
private boolean[] visited;//判断顶点是否被访问过
private int[] Begin;
private int[] End;
private int Count=0;
private int Tree[];//树状数组
public Main(int k,List<ArrayList<Integer>> G){
this.k=k;
this.G=G;
visited = new boolean[k+1];
Begin=new int[k+1];
End=new int[k+1];
Tree=new int[k+1];
}
public int getBegin(int i){
return Begin[i];
}
private void cl(){
for(int i=0;i<=k;i++)
visited[i]=false;
}
private int getEnd(int i){
return End[i];
}
public boolean getVis(int i){
return visited[i];
}
private void setVis(int i,boolean fal){
visited[i]=fal;
}
private int lowbit(int i) {
return i&(-i);
}
void Update(int i,int Num){
while(i<= k){
Tree[i] += Num;
i += lowbit(i);
}
}
int Sum(int i){
int sum = 0;
while(i>0){
sum += Tree[i];
i -= lowbit(i);
}
return sum;
}
public static void main(String[] args) throws IOException{
StreamTokenizer sc = new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
int k;
sc.nextToken();
k = (int) sc.nval; //顶点数
List<ArrayList<Integer>> G;
//构建邻接表
G = new ArrayList<ArrayList<Integer>>();
for(int i = 0;i<=k;i++)
G.add(new ArrayList<Integer>());//初始化邻接表
for (int i = 1; i <k; i++) {
sc.nextToken();
int u = (int) sc.nval;
sc.nextToken();
int v = (int) sc.nval;
if(!G.get(u).contains(v)) {//避免重边的情况比如a b可能出现两次的情况
G.get(u).add(v);
}
//对于无向图
if(!G.get(v).contains(u)) {
G.get(v).add(u);
}
}
Main ma=new Main(k,G);
ma.dfs(1);
for(int i = 1;i <= k;i++){
ma.Update(i,1);
}
sc.nextToken();
int M=(int) sc.nval;
ma.cl();
for(int i = 0;i < M;i++){
sc.nextToken();
String Op=sc.sval;
sc.nextToken();
int Num=(int) sc.nval;
if(Op.equals("C")){
if(!ma.getVis(Num))
ma.Update(ma.getBegin(Num),-1);//摘苹果
else
ma.Update(ma.getBegin(Num),1);//长一个
ma.setVis(Num,!ma.getVis(Num));
}else if(Op.equals("Q")){
System.out.printf("%d\n",ma.Sum(ma.getEnd(Num))-ma.Sum(ma.getBegin(Num)-1));
}
}
}
// 深搜
private void dfs(int v) {
Begin[v] = ++Count;
visited[v] = true;
//System.out.print(v+" ");
for (int i = 0; i <G.get(v).size(); i++) {
//递归调用搜索没有被访问过的当前节点的下一个节点(邻接点)
int k=G.get(v).get(i);
if (!visited[k])
dfs(k);
}
End[v] = Count;
}
}
源码: