poj3321-Apple Tree(DFS序+樹狀數組)

Apple Tree
Time Limit: 2000MS   Memory Limit: 65536K
Total Submissions: 36442   Accepted: 10894

Descriptionios

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.app

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?ide

 

 

Inputui

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 beginningspa

Output.net

For every inquiry, output the correspond answer per line.

Sample Input3d

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

Sample Outputcode

3
2

題意:給出了一棵樹,樹有不少的樹杈,標號分別爲1-n,如上圖所示,初始狀態時,每一個的樹杈位置都有一個蘋果,有m個操做,操做(c num)是若是num號樹杈有蘋果,就摘掉,不然這個樹杈上就會長出蘋果;操做(Q num)表示求以第num個樹杈爲根的子樹共有多少蘋果。
思路:這題能夠用dfs序給樹杈從新標號,使得每一棵子樹的序號都是連續的,而後就將樹狀結構轉換爲了線性結構,再使用樹狀數組求和就是求子樹的全部蘋果數了。

DFS序粗講:所謂dfs序就是一棵樹上每一個節點在dfs先序遍歷中的進出棧的時間序列。以下面這棵樹:
 

它的dfs序就是:blog

上面的遍歷結果中每一個點都出現兩次,由於一次是進棧,一次出棧。

咱們能夠發現,以每一個節點做爲根節點的子樹,這棵子樹中的全部節點在dfs序中都處於根節點中間。

例如:以B爲根節點的子樹,有BEFK四個點,而在dfs序中,這四個點的遍歷順序是相連的,爲BEEFKKFB,EFK做爲子節點,遍歷的順序在B進棧以後,而又在B出棧以前。驗證能夠發現,每個節點都知足這一性值。

因此,咱們按照dfs序從新給各個節點編號,每一個節點記錄兩個值,一個是進棧的時間,一個是出棧的時間。以下圖:

這棵樹按dfs先序遍歷以後得到了如上圖的編號,每一個點都有其進棧的時間和出棧的時間,二者造成了一個區間,圖中每一個點的進棧時間都不一樣,咱們就以進棧時間點做爲新的編號(根據寫法不一樣也能夠是出棧時間各不一樣)。咱們能夠發現,若以某個節點做爲根節點,那麼它的子樹上的全部點的的編號都在根節點的區間範圍內。例如上圖中的點4,它的新編號爲5,區間5-7,它的兩個子節點編號分別爲6,7;節點2的編號爲2,區間爲2-3,子節點新編號爲3(舊編號爲5)。

知道這一點以後,咱們就能夠來求以某個節點爲根的子樹的值的和了。好比求上圖中4號節點爲根的子樹的和,則就是求新編號區域爲5-7的和,這是連續的,用樹狀數組就好了,也便是sum(7)-sum(4)。

 

參考博客:https://blog.csdn.net/qq_39670434/article/details/78425125

具體操做看代碼:

  1 #include<iostream>
  2 #include<cstring>
  3 #include<cstdio>
  4 #include<string>
  5 #include<cmath>
  6 #include<algorithm>
  7 #include<stack>
  8 #include<climits>
  9 #include<map> 
 10 #include<queue>
 11 #define eps 1e-7
 12 #define ll long long
 13 #define inf 0x3f3f3f3f
 14 #define pi 3.141592653589793238462643383279
 15 using namespace std;
 16 const int MAXN = 1e5+7;
 17 
 18 struct Edge{
 19     int next,to;
 20 }edge[MAXN];
 21 int head[MAXN],n,m,cnt,in[MAXN],out[MAXN],visit[MAXN],c[MAXN];
 22 
 23 void ADD(int beg,int end) //鏈式前向心建樹 
 24 {
 25     edge[cnt].next = head[beg];
 26     edge[cnt].to = end;
 27     head[beg] = cnt++;
 28 }
 29 
 30 void DFS(int u) //得到dfs序 
 31 {
 32     visit[u] = 1; //標記節點已經被範圍(此題能夠沒有) 
 33     in[u] = ++cnt; //記錄節點u進棧的時間 
 34     for(int i=head[u]; i!=-1; i=edge[i].next) //遍歷節點u全部的子節點 
 35     {
 36         int j = edge[i].to;  
 37         if(!visit[j]) DFS(j); //搜索子節點 
 38     }
 39     out[u] = cnt; //記錄節點u出棧的時間 
 40 }
 41 
 42 int lowBit(int x)
 43 {
 44     return x&(-x);
 45 }
 46 
 47 void add(int x,int num)
 48 {
 49     for(int i=x; i<=n; i+=lowBit(i))
 50         c[i] += num;
 51 }
 52 
 53 int query(int x)
 54 {
 55     int ans = 0;
 56     for(int i=x; i>0; i-=lowBit(i))
 57         ans += c[i];
 58     return ans;
 59 }
 60 
 61 int main()
 62 {
 63     int t;
 64     char ques[2];
 65     while(scanf("%d",&n)!=EOF)
 66     {
 67         fill(head,head+n+5,-1);
 68         fill(visit,visit+n+5,0);
 69         cnt = 0;
 70         
 71         int beg,end;
 72         for(int i=0; i<n-1; ++i)
 73         {
 74             scanf("%d%d",&beg,&end);
 75             ADD(beg,end);
 76         }
 77         cnt = 0;
 78         DFS(1); //dfs得到新的編號 
 79 
 80         c[0] = 0;    
 81         for(int i=1; i<=n; ++i) add(i,1); //樹狀數組給每一個節點賦值,由於題目初始狀態是每一個節點都有蘋果 
 82         
 83         cin>>m;
 84         while(m--)
 85         {
 86             scanf("%s%d",ques,&t);
 87             if(ques[0] == 'C')
 88             {
 89                 if(visit[t] == 1) //判斷此節點是否有蘋果 
 90                 {
 91                     
 92                     add(in[t],-1); //有蘋果就減去 
 93                     visit[t] = 0; //而後標記爲沒有蘋果 
 94                 }
 95                 else
 96                 {
 97                     add(in[t],1); //沒有蘋果就加上 
 98                     visit[t] = 1;  //而後標記爲有 
 99                 }
100             }
101             else
102             {
103                 int ans = query(out[t]) - query(in[t]-1); //計算子樹的蘋果數 
104                 printf("%d\n",ans);
105             }
106         }
107     }
108     return 0;
109 }
相關文章
相關標籤/搜索