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

POJ 3321 Apple Tree 【树形结构转变为线性结构+线段树OR树状数组】

2015-08-12 01:30 603 查看
Apple Tree

Time Limit: 2000MSMemory Limit: 65536K
Total Submissions: 21587Accepted: 6551
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
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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: