POJ 3321 Apple Tree 【树形结构转变为线性结构+线段树OR树状数组】
2015-08-12 01:30
603 查看
Apple Tree
POJ 3321
链接:
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
For every inquiry, output the correspond answer per line.
Sample Input
Sample Output
如下图,可以看到,由于普通的树并不具有区间的性质,所以在考虑使用线段树作为解题思路时,需要对给给定的数据进行转化,首先对这棵树进行一次dfs遍历,记录dfs序下每个点访问起始时间与结束时间,记录起始时间是前序遍历,结束时间是后序遍历,同时对这课树进行重标号。
Step 2:
如下图,DFS之后,那么树的每个节点就具有了区间的性质。
那么此时,每个节点对应了一个区间,而且可以看到,每个节点对应的区间正好“管辖”了它子树所有节点的区间,那么对点或子树的操作就转化为了对区间的操作。
【PS: 如果对树的遍历看不懂的话,不妨待会对照代码一步一步调试,或者在纸上模拟过程~】
Step 3:
这个时候,每次对节点进行更新或者查询,就是线段树和树状数组最基本的实现了…
Time Limit: 2000MS | Memory Limit: 65536K | |
Total Submissions: 21587 | Accepted: 6551 |
链接:
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
For every inquiry, output the correspond answer per line.
Sample Input
3 1 2 1 3 3 Q 1 C 2 Q 1
Sample Output
3 2
励志一下
每一个你讨厌的现在,都有一个不够努力的曾经题外话
这个题目我认为出得特别好,非常启发思维,线段树专题必刷之题啊!!!话不扯远了,让咱们言归正传,开始讲题。题意
一棵具有n个节点的树,一开始,每个节点上都有一个苹果。现在给出m组操作:(C,i)是摘掉第i个节点上面的苹果(若苹果不存在,则为加上一个苹果),(Q,i)是查询以第i个节点为根的子树有几个苹果(包括第i个节点)。分析
Step 1:如下图,可以看到,由于普通的树并不具有区间的性质,所以在考虑使用线段树作为解题思路时,需要对给给定的数据进行转化,首先对这棵树进行一次dfs遍历,记录dfs序下每个点访问起始时间与结束时间,记录起始时间是前序遍历,结束时间是后序遍历,同时对这课树进行重标号。
Step 2:
如下图,DFS之后,那么树的每个节点就具有了区间的性质。
那么此时,每个节点对应了一个区间,而且可以看到,每个节点对应的区间正好“管辖”了它子树所有节点的区间,那么对点或子树的操作就转化为了对区间的操作。
【PS: 如果对树的遍历看不懂的话,不妨待会对照代码一步一步调试,或者在纸上模拟过程~】
Step 3:
这个时候,每次对节点进行更新或者查询,就是线段树和树状数组最基本的实现了…
代码实现
那我下面分别 给出线段树和树状数组的两种实现吧。/****************************>>>>HEADFILES<<<<****************************/ #include <set> #include <map> #include <list> #include <cmath> #include <queue> #include <vector> #include <cstdio> #include <string> #include <cstring> #include <iomanip> #include <iostream> #include <sstream> #include <algorithm> using namespace std; /****************************>>>>>DEFINE<<<<<*****************************/ #define fst first #define snd second #define root 1,N,1 #define lson l,mid,rt<<1 #define rson mid+1,r,rt<<1|1 #define PB(a) push_back(a) #define MP(a,b) make_pair(a,b) #define CASE(T) for(scanf("%d",&T);T--;) #define FIN freopen("input.txt","r",stdin) #define FOUT freopen("output.txt","w",stdout) //#pragma comment(linker, "/STACK:1024000000,1024000000") typedef __int64 LL; typedef pair<int,int> PII; const int INF = 0x3f3f3f3f; const int maxn = 100000 + 5; /****************************>>>>SEPARATOR<<<<****************************/ struct Node { int fir,las; }nodes[maxn]; vector<vector<int> > G; bool vis[maxn]; int segtree[maxn << 2]; int G_Mark, N, M, u, v; void init() { G.resize(N+2); G_Mark = 0; G.clear(); memset(vis, false, sizeof(vis)); } void DFS(int x) { vis[x] = true; nodes[x].fir = ++G_Mark; for(int i = 0; i < G[x].size(); i++) { if(vis[G[x][i]]) continue; DFS(G[x][i]); } nodes[x].las = G_Mark; } inline void PushUp(int rt) { segtree[rt] = segtree[rt << 1] + segtree[rt << 1 | 1]; } void Build(int l, int r, int rt) { segtree[rt] = r - l + 1; if(l == r) return; int mid = (l + r) >> 1; Build(lson); Build(rson); } void Update(const int& pos, int l, int r, int rt) { if(l == r) { segtree[rt] ^= 1; return; } int mid = (l + r) >> 1; if(pos <= mid) Update(pos, lson); else Update(pos, rson); PushUp(rt); } int Query(const int& L, const int& R, int l, int r, int rt) { if(L <= l && r <= R) return segtree[rt]; int mid = (l + r) >> 1, ret = 0; if(L <= mid) ret += Query(L, R, lson); if(R > mid) ret += Query(L, R, rson); return ret; } int main() { // FIN; while(~scanf("%d", &N)) { init(); for(int i = 0; i < N - 1; i++) { scanf("%d %d", &u, &v); G[u].PB(v); G[v].PB(u); } DFS(1); scanf("%d", &M); char Op[5]; int x, pos, L, R, ans; Build(root); for(int i = 0; i < M; i++) { scanf("%s %d", Op, &x); if(Op[0] == 'C') { pos = nodes[x].fir; Update(pos, root); } else { L = nodes[x].fir, R = nodes[x].las; ans = Query(L, R, root); printf("%d\n", ans); } } } return 0; }
/****************************>>>>HEADFILES<<<<****************************/ #include <set> #include <map> #include <list> #include <cmath> #include <queue> #include <vector> #include <cstdio> #include <string> #include <cstring> #include <iomanip> #include <iostream> #include <sstream> #include <algorithm> using namespace std; /****************************>>>>>DEFINE<<<<<*****************************/ #define fst first #define snd second #define root 1,N,1 #define lson l,mid,rt<<1 #define rson mid+1,r,rt<<1|1 #define PB(a) push_back(a) #define MP(a,b) make_pair(a,b) #define CASE(T) for(scanf("%d",&T);T--;) #define FIN freopen("input.txt","r",stdin) #define FOUT freopen("output.txt","w",stdout) //#pragma comment(linker, "/STACK:1024000000,1024000000") typedef __int64 LL; typedef pair<int,int> PII; const int INF = 0x3f3f3f3f; const int maxn = 100000 + 5; /****************************>>>>SEPARATOR<<<<****************************/ struct Node { int fir,las; }nodes[maxn]; vector<vector<int> > G; bool vis[maxn]; int C[maxn],S[maxn]; int G_Mark, N, M, u, v; void init() { G.resize(N+2); G_Mark = 0; G.clear(); memset(C,0,sizeof(C)); memset(vis, false, sizeof(vis)); } void DFS(int x) { vis[x] = true; nodes[x].fir = ++G_Mark; for(int i = 0; i < G[x].size(); i++) { if(vis[G[x][i]]) continue; DFS(G[x][i]); } nodes[x].las = G_Mark; } inline int lowbit(int x) { return x&(x^(x-1)); } void Add(int pos,int val) { while(pos <= N) { C[pos] += val; pos += lowbit(pos); } } int Sum(int pos) { int ret = 0; while(pos > 0) { ret += C[pos]; pos -= lowbit(pos); } return ret; } int main() { // FIN; while(~scanf("%d", &N)) { init(); for(int i = 0; i < N - 1; i++) { scanf("%d %d", &u, &v); G[u].PB(v); G[v].PB(u); } DFS(1); scanf("%d", &M); char Op[5]; int x, pos, L, R, ans; for(int i = 1;i <= N;i++) Add(i,1),S[i] = 1; for(int i = 0; i < M; i++) { scanf("%s %d", Op, &x); if(Op[0] == 'C') { pos = nodes[x].fir; S[pos] ^= 1; int add = S[pos] == 1 ? 1 : -1; Add(pos,add); } else { L = nodes[x].fir, R = nodes[x].las; if(L == 1) ans = Sum(R); else ans = Sum(R) - Sum(L-1); printf("%d\n", ans); } } } return 0; }
相关文章推荐
- iOS包管理工具Cocoapods的安装与使用
- Ray Wenderlich的swift教程02--引用类型和值类型
- 基于socket的心跳长连接
- 编译cocos2dx 工程,ndk-build 报错:
- 在Android上面如何使用带有心跳检测的Socket
- iOS- JSon和Xml解析,与服务器交互数据的解析详解与使用,各种解析方式详解
- Android 史上最强多语言国际化,不仅第一次会跟随系统,而且会保存用户的语言设置
- 关于android性能,内存优化
- iOS 常用框架收集
- iOS项目开发实战——使用异步请求获取网页HTML源代码
- 打电话,发短信,发邮件,app跳转
- 浅谈Android列表ListView下拉刷新控件的实现(一)
- Android Toast封装
- 02_07 JSP内置对象之application
- 三星电视支付——在电视上购买APP和游戏
- cocos2d 3d
- 微信无法使用支付宝?
- 在 iOS 应用中直接跳转到 AppStore 的方法
- struts1_MappingDispatchAction
- 千锋扣丁学堂 如何学习android高级编程