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 [题意] 给定一棵树,给定这棵树的根 对于每个结点,统计子树中编号比他小的结点个数 编号从小到大一次输出 ...
随机推荐
- 微软Insider Dev Tour 活动
总述 Insider Dev Tour 将在6月全球29个城市中展开.这次活动是通过与微软全球MVPs和RD合作进行的,并涵盖了微软最新的开者方面的最新消息. 日期提示 2018年5月7日 : 暂无其 ...
- python 运行出现flask运行时提示出错了或者报服务器出错,ValueError: View function did not return a response
python manage.py runserver -d
- Cordova页面加载外网图片失败,Refused to load the image
原文:Cordova页面加载外网图片失败,Refused to load the image 1.使用Cordova页面加载外网图片失败,抛出异常 Refused to load the image ...
- Win8Metro(C#)数字图像处理--2.19图像水平镜像
原文:Win8Metro(C#)数字图像处理--2.19图像水平镜像 [函数名称] 图像水平镜像函数MirrorXProcess(WriteableBitmap src) [函数代码] ...
- Android零基础入门第40节:自定义ArrayAdapter
原文:Android零基础入门第40节:自定义ArrayAdapter ListView用起来还是比较简单的,也是Android应用程序中最重要的一个组件,但其他ListView可以随你所愿,能够完成 ...
- oracle解析
Oracle数据库中的CURSOR分为两种类型:Shared Cursor 和 Session Cursor 1,Shared Cursor Oracle里的第一种类型的Cursor就是Shared ...
- UWP-标题栏”后退“按钮
原文:UWP-标题栏"后退"按钮 标题栏”后退“按钮,系统级导航 应用必须启用所有硬件和软件系统后退按钮的后退导航.执行此操作的方法是注册 BackRequested 事件的侦听器 ...
- Delphi事件的广播
原文地址:Delphi事件的广播 转作者:MondaySoftware 明天就是五一节了,辛苦了好几个月,借此机会应该尽情放松一番.可是想到Blog好久没有写文章,似乎缺些什么似的.这几个月来在项目中 ...
- 使用 Napa 创建并调试一个 Office 内容应用 – Hello World
原文地址:http://simpeng.net/office-add-in/%e4%bd%bf%e7%94%a8-napa-%e5%88%9b%e5%bb%ba%e5%b9%b6%e8%b0%83%e ...
- “真正的工作不是说的天花乱坠”,Torvalds 说, “而是在于细节”(Torvalds 认为成功的项目都是99%的汗水和1%的创新)
在刚刚结束的加利福尼亚州的开源领袖峰会(2月14日-16日)上,Linus Torvalds 接受了外媒的采访,分享了他如何管理 Linux kernel 的开发以及他对工作的态度. “真正的工作不是 ...