您的位置:首页 > 移动开发

【POJ】3321 Apple Tree(DFS树的应用)

2015-02-25 17:34 246 查看
题目大意:这边给一棵苹果树,每个节点可以生出多个分支,每个分支可以有0或者1个苹果

现在给出每个节点与分支的情况。以及相应的操作。

思路:

一开始确实是看懵了,想不到为什么是线段树或者是树状数组,这边给的是一棵树,而线段树或者树状数组都是一维数组,所以这边就涉及到一个将树转换成一维数组的方法,便是对树进行dfs。详细看代码吧,初学也不知道怎么表达感悟,等以后加深印象再多写一点内容吧。

线段树做法:比较粗糙,所以在时间上不如树状数组

#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
#define MAX 100005
#define ls rt<<1
#define rs ls|1
#define m (r+l)>>1
int col[MAX << 2];
int sum[MAX << 2];
int head[MAX];
int n;
int num;
int time;

struct tree
{
int v, next;
}edg[MAX];

struct f
{
int s, e;
}s[MAX];

/*
这是图中一种建树的方法
*/
void addedge(int a, int b)
{
edg[num].v = b;
edg[num].next = head[a];
head[a] = num++;
}
/*
形象的描述的话,就是给这个节点标记上开始搜索和结束搜索的编号。
一个节点的结束编号恰好是以这个节点为子树的最后一个节点的结束编号。
通过这样就可以明白我们建立的是一个一维数组与树节点的映射关系。
例如
1 2
1 3
对应的便是       1 3 2
而对应的一维数组是 1 2 3
其中1的开始编号是1,结束编号是3。这边结合图形想象一下就可以了。
*/
void dfs(int a)
{
s[a].s = ++time;
for (int i = head[a]; i != -1; i = edg[i].next)
dfs(edg[i].v);
s[a].e = time;
}

void uprt(int rt)
{
if (col[rt])
{
sum[rt] += col[rt];
col[rs] += col[rt];
col[ls] += col[rt];
col[rt] = 0;
}
}

void uprt2(int rt)
{
sum[rt] = sum[rs] + sum[ls];
}
void build(int l, int r, int rt)
{
if (l == r)
{
col[rt] = 0;
sum[rt] = 1;
return;
}
int mid = m;
build(l, mid, ls);
build(mid + 1, r, rs);
uprt2(rt);
}

void updata(int L,int R,int c, int l, int r, int rt)
{
if (L <= l&&r <= R)
{
col[rt] = c;
uprt(rt);
return;
}
uprt(rt);
int mid = m;
if (L <= mid)
updata(L, R, c, l, mid, ls);
if (mid < R)
updata(L, R, c, mid + 1, r, rs);
uprt2(rt);
}

int query(int L, int R, int l, int r, int rt)
{
if (L <= l&&r <= R)
return sum[rt];
uprt(rt);
int ans = 0;
int mid = m;
if (L <= mid)
ans += query(L, R, l, mid, ls);
if (mid < R)
ans += query(L, R, mid + 1, r, rs);
return ans;
}

int main()
{
int n;
cin >> n;
int a, b;
num = 0;
time = 0;
memset(head, -1, sizeof(head));
for (int i = 0; i < n-1; i++)
{
scanf("%d%d", &a, &b);
addedge(a, b);
}
dfs(1);
build(1, n, 1);
int t;
cin >> t;
cin.get();
char c;
while (t--)
{
scanf("%c%d%*c", &c, &a);
if (c == 'C')
{
b = query(s[a].s, s[a].s, 1, n, 1);
if (b == 1)
updata(s[a].s, s[a].s, -1, 1, n, 1);
else
updata(s[a].s, s[a].s, 1, 1, n, 1);
}
else
cout << query(s[a].s, s[a].e, 1, n, 1) << endl;
}
}


树状数组做法:

#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define MAX 100005
int head[MAX];
int num;
int time;
int sum[MAX];
int n;
struct tree
{
int v, next;
}edg[MAX];
struct f
{
int s, e;
}s[MAX];

void addedg(int a, int b)
{
edg[num].v = b;
edg[num].next = head[a];
head[a] = num++;
}

void dfs(int a)
{
s[a].s = ++time;
for (int i = head[a]; i != -1; i = edg[i].next)
dfs(edg[i].v);
s[a].e = time;
}
int lowbit(int k)
{
return k&(-k);
}

void add(int s, int k)
{
while (s <= n)
{
sum[s] += k;
s += lowbit(s);
}
}

int getsum(int s)
{
int i = 0;
while (s > 0)
{
i += sum[s];
s -= lowbit(s);
}
return i;
}

int main()
{
cin >> n;
int a, b;
memset(head, -1, sizeof(head));
num = 0;
time = 0;
for (int i = 0; i < n - 1; i++)
{
scanf("%d%d", &a, &b);
addedg(a, b);
}
dfs(1);
for (int i = 1; i <= n; i++)
add(i, 1);
char c;
int t;
scanf("%d%*c", &t);
while (t--)
{
scanf("%c%d%*c", &c, &a);
if (c == 'C')
{
if (getsum(s[a].s) - getsum(s[a].s - 1) == 1)
add(s[a].s, -1);
else
add(s[a].s, 1);
}
else
{
cout << getsum(s[a].e) - getsum(s[a].s - 1) << endl;;
}
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: