关于树状数组:参看:http://128kj.iteye.com/blog/1743633
POJ3321 题意:
一棵具有n个节点的树,一开始,每个节点上都有一个苹果。现在给出m组动态的操作:
(C,i)是摘掉第i个节点上面的苹果(若苹果不存在,则为加上一个苹果),(Q,i)是查询以第i个节点为根的子树有几个苹果(包括第i个节点)。
输入是叉之间的关系,
1 2
1 3
就是主干上面两个叉分别是2 和3.
样例:
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));
- }
- }
- }
转载于:https://blog.51cto.com/shuaigee/1139377