POJ Apple Tree (树状数组 + dfs序)
2015-09-06 10:52
218 查看
题目大意:给你一颗 n 个结点的树 , 结点编号为1 , 2 , … , n 。 以 1 作为根节点。每个结点的值初始化为1 , 然后有 q 种操作 。
1. C x 表示将结点 x 的值取反(即 0 变 1 , 1 变 0)
2. Q x 表示查询以结点 x 为根结点的子树的值得总和
其中 , n 和 q 的最大值都是10W.
这个题一开始的想法是直接在树上进行操作, 每个结点维护以该结点的为根的子树的值。这样查找结点 x 的时间复杂度为O(n) , 所以总的时间复杂度为 O(n * q) 。 肯定超时。
由这两个操作的特性(单点修改, 求区间和) 很容易想到用树状数组来实现, 但问题在于树状数组是在线性的结构上应用的, 而这个题给你的是一颗树 。 因此, 我们需要对这棵树稍作转化, 将它转化为线性结构。 只需要对这棵树做一个DFS , 维护两个数组s 和 e 。 分别记录 该结点的 起始dfs序 和 终止dfs序。 s[x] 和 e[x] 之间的结点即为它的子结点。
修改操作: add(s[x] , d)
求和做操: sum(e[x]) - sum(s[x] - 1)
另外这个题有卡vector , 用vector 存储树的话, 会超时。
1. C x 表示将结点 x 的值取反(即 0 变 1 , 1 变 0)
2. Q x 表示查询以结点 x 为根结点的子树的值得总和
其中 , n 和 q 的最大值都是10W.
这个题一开始的想法是直接在树上进行操作, 每个结点维护以该结点的为根的子树的值。这样查找结点 x 的时间复杂度为O(n) , 所以总的时间复杂度为 O(n * q) 。 肯定超时。
由这两个操作的特性(单点修改, 求区间和) 很容易想到用树状数组来实现, 但问题在于树状数组是在线性的结构上应用的, 而这个题给你的是一颗树 。 因此, 我们需要对这棵树稍作转化, 将它转化为线性结构。 只需要对这棵树做一个DFS , 维护两个数组s 和 e 。 分别记录 该结点的 起始dfs序 和 终止dfs序。 s[x] 和 e[x] 之间的结点即为它的子结点。
修改操作: add(s[x] , d)
求和做操: sum(e[x]) - sum(s[x] - 1)
另外这个题有卡vector , 用vector 存储树的话, 会超时。
代码
#include <iostream> #include <cstring> #include <cstdio> using namespace std; const int maxn = 100010; int c[maxn] , a[maxn] , n; int s[maxn] , e[maxn] , cnt; int head[maxn] , num; struct Node { int v , next; }node[maxn*2]; void AddEdge(int from , int to) { node[num].v = to; node[num].next = head[from]; head[from] = num++; } int vis[maxn]; void DFS(int cur) { s[cur] = ++cnt; vis[cur] = 1; for(int i = head[cur]; i != -1 ; i = node[i].next) { int u = node[i].v; if(!vis[u]) DFS(u); } e[cur] = cnt; } int lowbit(int x) {return x & (-x);} void add(int x , int d) { while(x <= n) { c[x] += d; x += lowbit(x); } } int sum(int x) { int rel = 0; while(x > 0) { rel += c[x]; x -= lowbit(x); } return rel; } int main() { while(scanf("%d" , &n) != EOF) { memset(head , -1 , sizeof(head)); memset(vis , 0 , sizeof(vis)); memset(c , 0 , sizeof(c)); cnt = num = 0; for(int i = 1; i < n; i++) { int u , v; scanf("%d%d" , &u , &v); AddEdge(u , v); AddEdge(v , u); } DFS(1); for(int i = 1; i <= n; i++) {add(i , 1); a[i] = 1;} int q; scanf("%d" , &q); for(int i = 0; i < q; i++) { char type[10]; int x; scanf("%s%d" , type , &x); if(type[0] == 'Q') printf("%d\n" , sum(e[x]) - sum(s[x] - 1)); else { int d; if(a[x]) d = -1; else d = 1; add(s[x] , d); a[x] += d; } } } return 0; }
相关文章推荐
- Lua和C语言的交互详解
- 关于C语言中参数的传值问题
- 简要对比C语言中三个用于退出进程的函数
- 深入C++中API的问题详解
- 基于C语言string函数的详解
- C语言中fchdir()函数和rewinddir()函数的使用详解
- C语言内存对齐实例详解
- 使用C语言判断英文字符大小写的方法
- c语言实现的带通配符匹配算法
- C语言实现顺序表基本操作汇总
- C语言中计算正弦的相关函数总结
- 使用C语言详解霍夫曼树数据结构
- 探讨C语言的那些小秘密之断言
- C语言实现BMP转换JPG的方法
- 深入探讨C语言中局部变量与全局变量在内存中的存放位置
- C语言查找数组里数字重复次数的方法
- C语言泛型编程实例教程
- C语言中使用lex统计文本文件字符数
- 在C语言中转换时间的基本方法介绍
- C语言进制转换代码分享