Time Limit: 2000MS | Memory Limit: 65536K | |
Total Submissions: 16180 | Accepted: 4836 |
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
"C 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
"Q 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
Sample Input
3 1 2 1 3 3 Q 1 C 2 Q 1
Sample Output
3 2
題目大意級是說,給你一顆樹,最初每個節點上都有一個蘋果,有兩種操作:修改(即修改某一個節點,修改時這一個節點蘋果從有到無,或從無到有)和查詢(查詢某一個節點他的子樹上有多少個蘋果)。
由於此題數據比較大(N<=10^5),而且不是標准的二叉樹,所以這里我們隊每一個節點重新編號,另外為每一個節點賦一個左值和一個右值,表示這個節點的管轄范圍。
上圖也就是DFS搜索的時候做標記的過程,這樣新的編號為1~6的節點所管轄的范圍分別就是[1,6] [2,4] [3,3] [4,4] [5,6] [6,6],其中左邊的是左值,右邊的是右值,節點1的區間是[1,6],正好這棵子樹有6個節點,其他也一樣
那我們吧新的節點放進樹狀數組時
那我們求出每一個節點從1~左值的和 和 1~右值的和 他們的差就是這個節點的子樹的所有的和(即這棵子樹蘋果數目)
可以百度下看看樹狀數組的實現
最后每輸入一組數據就進行依次操作就可以了
1 #include <cstdio> 2 #include <cstring> 3 #include <vector> 4 #define MAXN 100005 5 #define mem(a) memset(a, 0, sizeof(a)) 6 using namespace std; 7 8 int TreeArray[MAXN], Left[MAXN], Right[MAXN], Fork[MAXN]; 9 typedef vector<int> Ve; 10 vector<Ve>Edge(MAXN); 11 int N,M; 12 int key; 13 14 void init()//初始化數組和 15 { 16 mem(Left); mem(Right); 17 mem(Fork); mem(TreeArray); 18 for(int i=0;i<MAXN;i++)Edge[i].clear(); 19 } 20 21 void DFS(int node)//為每一個node添加一個左值和右值,表示這個節點所 22 { 23 Left[node] = key; 24 for(int i=0;i<Edge[node].size();i++) 25 { 26 key+=1; 27 DFS(Edge[node][i]); 28 } 29 Right[node] = key; 30 } 31 32 int LowBit(int x)//返回的是2^k 33 { 34 return x & (x ^ (x-1)); 35 } 36 37 void Edit(int k, int num)//修改節點k,如果是添加一個,代入1,刪除一個代入-1 38 { 39 while(k <= N) 40 { 41 TreeArray[k] += num; 42 k += LowBit(k); 43 } 44 } 45 46 int GetSum(int k)//得到1...k的和 47 { 48 int sum = 0; 49 while(k>=1) 50 { 51 sum += TreeArray[k]; 52 k -= LowBit(k); 53 } 54 return sum; 55 } 56 57 void ReadDataAndDo() 58 { 59 int a,b; 60 char ch; 61 for(int i=1;i<N;i++)//輸入a,b把邊存放在容器里面 62 { 63 scanf("%d%d", &a, &b); 64 Edge[a].push_back(b); 65 } 66 key = 1; DFS(1);//為每一個節點對應一個左邊界和右邊界,他自己就存放在左邊界里面,而它的管轄范圍就是左邊界到右邊界 67 for(int i=1;i<=N;i++) 68 { 69 Fork[i] = 1;//最初每個Fork上都有一個蘋果 70 Edit(i,1);//同時更新樹狀數組的值 71 } 72 scanf("%d%*c", &M); 73 for(int i=0;i<M;i++) 74 { 75 scanf("%c %d%*c", &ch, &b); 76 if(ch == 'Q')//b的子樹就是[Left[b], right[b]] 77 { 78 printf("%d\n", GetSum(Right[b]) - GetSum(Left[b]-1)); 79 } 80 else 81 { 82 if(Fork[b]) Edit(Left[b],-1);//由於每個節點的編號就是它的左值,所以直接修改左節點 83 else Edit(Left[b],1); 84 Fork[b] = !Fork[b];//變為相反的狀態 85 } 86 } 87 } 88 89 int main() 90 { 91 while(~scanf("%d", &N)) 92 { 93 init(); 94 ReadDataAndDo(); 95 } 96 return 0; 97 }