POJ 3321:Apple Tree + HDU 3887:Counting Offspring(DFS序+树状数组)
http://poj.org/problem?id=3321
http://acm.hdu.edu.cn/showproblem.php?pid=3887
POJ 3321:
题意:给出一棵根节点为1的边不一定的树,然后给出问题:询问区间和 或者 节点值更新。
HDU 3887:
题意:和POJ 3321的题意差不多,只不过对每个节点询问不包含该节点的区间和
思路:今天才学了下才知道有DFS序这种东西,加上树状数组处理一下区间和 和 节点更新。
DFS序大概就是我们在DFS遍历一棵树的时候,在进入这个节点的时候,我们用一个变量记录此时的时间(代码中用cnt表示,也是可以看做是目前已经遍历过的节点的数目),然后分别用一个数组表示开始搜索这个节点的时间,和离开这个节点的时间(代码中用st代表开始,用ed代表结束)。然后我们可以发现在这段时间里面遍历过的节点都是该节点的儿子,即例如HDU3887这组样例:
15 7
7 10
7 1
7 9
7 3
7 4
10 14
14 2
14 13
9 11
9 6
6 5
6 8
3 15
3 12
0 0
我们的遍历顺序是这样的:7 1 1 3 15 15 12 12 3 4 4 10 14 2 2 13 13 14 10 9 11 11 6 5 5 8 8 6 9 7(手打的。。)
分别对应的下标是这样的:例如根节点7,它管辖的范围从前到后全部是,说明它就是根节点了。那么它的范围是【1,30】。
int cnt = ;
void dfs(int u, int fa)
{
que[++cnt] = u;
for(int k = head[u]; ~k; k = edge[k].nxt){
int v = edge[k].v;
if( v == fa ) continue;
dfs(v, u);
}
que[++cnt] = u;
}
dfs(, -);
我这里用的是前向星存的图,然后从根节点7开始遍历。
我先用一个数组来装遍历过的点的顺序,即que数组为我上面列出来的那个序列。
然后我们就按下面这样处理
for(int i = ; i <= cnt; i++) {
if( st[que[i]] == ) st[que[i]] = i;
else se[que[i]] = i;
}
把开始的位置和结束的位置分别装在st数组和ed数组中。
然后我们就可以根据这些条件建立起树状数组了。
询问的区间和为Query( ed[node] ) - Query( st[node] - 1 ) / 2(因为我们重复计数了,每个节点枚举了两次) ,更新就是Update( ed[node], value ); Update( st[node], value );
下面给出HDU 3887 的代码。
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <iostream>
#include <vector>
using namespace std;
#define N 100010 int st[N], se[N], ans[N], cnt;
int bit[*N],que[*N];
int head[N], tot;
struct node
{
int v, nxt;
}edge[N*];
//vector <int> edge[N];
//dfs序 + 树状数组
void addedge(int u, int v)
{
edge[tot].v = v;
edge[tot].nxt = head[u];
head[u] = tot++;
} void dfs(int u, int fa)
{
que[++cnt] = u;
for(int k = head[u]; ~k; k = edge[k].nxt){
int v = edge[k].v;
if( v == fa ) continue;
dfs(v, u);
}
que[++cnt] = u;
} int lowbit(int x)
{
return x & (-x);
} void Update(int x, int value)
{
while( x <= cnt ) {
bit[x] += value;
x += lowbit(x);
}
} int Query(int x)
{
int ans = ;
while( x > ) {
ans += bit[x];
x -= lowbit(x);
}
return ans;
} int main()
{
int n,p;
while(scanf("%d%d", &n, &p), n + p) { memset(head, -, sizeof(head));
tot = ; memset(bit,,sizeof(bit));
memset(st,,sizeof(st));
// for(int i = 1; i <= n; i++)
// edge[i].clear();
for(int i = ; i < n; i++) {
int u, v;
scanf("%d%d", &u, &v);
addedge(u, v);
addedge(v, u);
// edge[u].push_back(v);
// edge[v].push_back(u);
}
cnt = ;
dfs(p, p); for(int i = ; i <= cnt; i++) {
if( st[que[i]] == ) st[que[i]] = i;
else se[que[i]] = i;
} for(int i = ; i <= cnt; i++) {
// printf("%d ", que[i]);
Update(i, );
}
putchar('\n');
//因为题意中要求子树中的节点不能比根节点的数大,因此从后往前枚举,
//然后删除掉枚举过的节点,这样就能保证后面的枚举中子树的点的数不会比根节点的大了
//而且题目的询问是不包含该询问的节点的,因此是(Query(se[i] - 1) - Query(st[i])) / 2
//而不是( Query(se[i]) - (Query[st[i]] - 1) ) / 2
for(int i = n; i > ; i--) {
ans[i] = (Query(se[i] - ) - Query(st[i])) / ;
Update(se[i], -);
Update(st[i], -);
} for(int i = ; i <= n; i++) {
printf("%d", ans[i]);
if( i == n ) printf("\n");
else printf(" ");
}
}
return ;
}
我根据上题的代码也写了一份POJ 3321的代码,顺利AC了之后,看了看别人的代码,发现自己处理的有点复杂 (就是MDZZ)。
先上一份看了别人之后修改过的DFS的代码
void dfs(int u, int fa)
{
st[u] = ++cnt;
for(int k = head[u]; ~k; k = edge[k].nxt){
int v = edge[k].v;
if( v != fa ) dfs(v, u);
}
ed[u] = cnt;
}
其实完全可以抛弃上一题的que数组,直接用这样的方式来处理st和ed数组。
虽然我觉得用que数组的话真的很好理解,但是变得比较冗杂了。
我们还是举HDU 3887的例子(谁让POJ 3321这个样例太不好举例了。。)
我们这样处理的话就是直接去掉我上面的重复的数字,变成:
node:7 1 3 15 12 4 10 14 2 13 9 11 6 5 8
st和ed两个数组对应的下标分别是:
st: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
ed:15 2 5 4 5 6 10 10 9 10 15 12 15 14 15 (对不齐,将就看看吧= =)
我们直接根据这样就可以建立一个树状数组了。
例如节点7的领域:【1,15】,
节点1的领域:【2,2】,
以此类推。
然后因为我们的树状数组变了,所以我们的询问和更新也肯定变了。
询问还是 【 st[node] - 1 ,ed[node] 】,只不过区间的值变小了,因为没有重复,我们不用对答案除以2了。
更新的区间就只要更新st[node]了,因为看上面,st[node]代表的是当下标取node时对应于该节点的左端点,所以只要更新st[node]就可以了。
还有这题可能卡了vector,我用的是前向星,一开始用vector超时了。
下面给出代码
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
#define N 100005
struct node
{
int v, nxt;
}edge[N*];
int bit[N], st[N], ed[N], head[N], mark[N], cnt, tot, n; void add(int u,int v)
{
edge[tot].v = v;
edge[tot].nxt = head[u];
head[u] = tot++;
edge[tot].v = u;
edge[tot].nxt = head[v];
head[v] = tot++;
} int lowbit(int x)
{
return x & (-x);
} int Query(int x)
{
int ans = ;
while( x > ){
ans += bit[x];
x -= lowbit(x);
}
return ans;
} void Update(int x, int value)
{
while( x <= n ){
bit[x] += value;
x += lowbit(x);
}
} void dfs(int u, int fa)
{
st[u] = ++cnt;
for(int k = head[u]; ~k; k = edge[k].nxt){
int v = edge[k].v;
if( v != fa ) dfs(v, u);
}
ed[u] = cnt;
} int main()
{
tot = , cnt = ;
memset(bit, , sizeof(bit));
memset(head, -, sizeof(head));
scanf("%d", &n);
for(int i = ; i < n; i++){
int u, v;
scanf("%d%d", &u, &v);
add(u, v);
}
for(int i = ; i <= n; i++){
Update(i, );
mark[i] = ;
} dfs(, -); int q;
scanf("%d", &q);
while(q--){
char s[];
int node;
scanf("%s%d", s, &node);
if(s[] == 'Q'){
int ans = Query(ed[node]) - Query(st[node] - );
printf("%d\n", ans);
}
else{
mark[node] *= -;
Update(st[node], mark[node]);
}
printf("%d %d\n", bit[st[]], bit[ed[]]);
}
return ;
}
//15
//1 10
//1 7
//1 9
//1 3
//1 4
//10 14
//14 2
//14 13
//9 11
//9 6
//6 5
//6 8
//3 15
//3 12
//8
//Q 1
//C 1
//C 3
//C 5
//Q 1
//C 1
//Q 1
//Q 5
POJ 3321:Apple Tree + HDU 3887:Counting Offspring(DFS序+树状数组)的更多相关文章
- hdu 3887 Counting Offspring dfs序+树状数组
Counting Offspring Time Limit: 15000/5000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Othe ...
- HDU 5293 Tree chain problem 树形dp+dfs序+树状数组+LCA
题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=5293 题意: 给你一些链,每条链都有自己的价值,求不相交不重合的链能够组成的最大价值. 题解: 树形 ...
- hdu 5877 Weak Pair dfs序+树状数组+离散化
Weak Pair Time Limit: 4000/2000 MS (Java/Others) Memory Limit: 262144/262144 K (Java/Others) Prob ...
- 刷题总结——Tree chain problem(HDU 5293 树形dp+dfs序+树状数组)
题目: Problem Description Coco has a tree, whose vertices are conveniently labeled by 1,2,…,n.There ar ...
- HDU 3887:Counting Offspring(DFS序+树状数组)
http://acm.hdu.edu.cn/showproblem.php?pid=3887 题意:给出一个有根树,问对于每一个节点它的子树中有多少个节点的值是小于它的. 思路:这题和那道苹果树是一样 ...
- HDU 5293 Annoying problem 树形dp dfs序 树状数组 lca
Annoying problem 题目连接: http://acm.hdu.edu.cn/showproblem.php?pid=5293 Description Coco has a tree, w ...
- Codeforces Round #225 (Div. 1) C. Propagating tree dfs序+树状数组
C. Propagating tree Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://codeforces.com/contest/383/p ...
- Codeforces Round #225 (Div. 1) C. Propagating tree dfs序+ 树状数组或线段树
C. Propagating tree Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://codeforces.com/contest/383/p ...
- 【DFS序+树状数组】HDU 3887 Counting Offspring
http://acm.hdu.edu.cn/showproblem.php?pid=3887 [题意] 给定一棵树,给定这棵树的根 对于每个结点,统计子树中编号比他小的结点个数 编号从小到大一次输出 ...
随机推荐
- 数字证书原理 good
文中首先解释了加密解密的一些基础知识和概念,然后通过一个加密通信过程的例子说明了加密算法的作用,以及数字证书的出现所起的作用.接着对数字证书做一个详细的解释,并讨论一下windows中数字证书的管理, ...
- G1 安装 Linux Debian system
开发Android第五步,G1 安装 Linux Debian system 在 G1 上安装 Linux Debian system (Debian ARMEL) 要具备以下条件: (a) 最好是 ...
- 【python】python调用adb
本期分享下python如何调用adb: 1.导入os模块 import os 2.python中调用adb命令语法 print("显示机型信息:") os.system('adb ...
- WPF 鼠标在图片Image上悬停时切换更改设置图片源Source
// 无效的写法,图片不会被切换 <Image Margin="0,0,0,0" Width="50" Height="50" Sou ...
- Android手机导出文件
因为要写联系人相关的东西,所以得把db导出来看看 第一步:Root手机 尝试了几个Root工具,发现就KingRoot能root 第二个:编写bat脚本 脚本内容是先将DB文件从/data/data ...
- 微信小程序把玩(十八)picker组件
原文:微信小程序把玩(十八)picker组件 picker选择器分为三种,普通选择器,时间选择器, 日期选择器 用mode属性区分,默认是普通选择器.测试时时间和日期点击无反应不知道是BUG还是啥!没 ...
- C#关于多线程的笔记
Thread thNetwork; thNetwork = new Thread(new ThreadStart(GetNetworkInfo));//创建一个线程 thNetwork.Start() ...
- CRS-2800: Cannot start resource 'ora.asm' as it is already in the INTERMEDIATE state on server ‘RAC02’
在安装ORACLE RAC的Grid Infrastructure时,在节点1运行/u01/app/11.2.0/grid/root.sh正常,当在节点2运行/u01/app/11.2.0/grid/ ...
- visual studio 2017 添加MSDN
原文:visual studio 2017 添加MSDN 1.启动VS2017的安装软件,点击更改,进行MSDN帮助组件添加安装. 2.在单个组件中找到"Help Viewer", ...
- memcached的使用一
1.安装memcached 需要一个memcache.exe文件,打开cmd窗口,切换到可执行文件目录,执行memcache -的install命令. 2.连接服务 做测试可以打开电脑的telnet ...