POJ 3321 树状数组,树转化为线性结构

题目链接
测试数据中边是 从上往下给的,也就是从根往叶子给的

大体思路
将树形结构变为线性结构
后序遍历整棵树,记录下遍历这个点的时间和结束遍历的时间,那么[a,b]就可以代表这棵子树。
我们用一个节点的结束时间来标识树状数组中的c[]。即sum(i)表示 所有 遍历结束的时间小于i的节点的权值和

#include 
#include
#include
#include

using namespace std;
const int maxn = 1e5+2;
int n,m,cnt=1;
struct Edge
{
    int u,v,next;
};
struct Apple
{
    int l,r;
}apple[maxn];
Edge edge[maxn];
int head[maxn],c[maxn],a[maxn];
void add(int u,int v)///链式前向星
{
    edge[cnt].u=u;
    edge[cnt].v=v;
    edge[cnt].next=head[u];
    head[u]=cnt++;
}
inline int lowbit(int x)
{
    return x&-x;
}
void dfs(int u)
{
    apple[u].l=cnt;
    for(int i = head[u];~i;i=edge[i].next)
    {
        dfs(edge[i].v);
    }
    apple[u].r=cnt++;
}
int sum(int x)
{
    int res=0;
    for(int i=x; i > 0; i-=lowbit(i)) {
        res+=c[i];
    }
    return res;
}
void change(int x)
{
    if(a[x]) {
        for(int i=x; i < cnt ; i+=lowbit(i)) {
            c[i]++;
        }
    }
    else {
        for(int i=x; i < cnt; i+=lowbit(i)) {
            c[i]--;
        }
    }
}
int main()
{
    memset(head,-1,sizeof head);
    memset(c,0,sizeof c);
    memset(apple,0,sizeof apple);
    scanf("%d",&n);
    for(int i = 0; i < n-1; ++i) {
        int u,v;
        scanf("%d%d",&u,&v);
        add(u,v);
    }
    cnt=1;
    dfs(1);
    for(int i = 1; i <= n; ++i) {
        a[i]=1;
        change(i);
    }
    char str[3];
    scanf("%d",&m);
    while(m--) {
        int op;
        scanf("%s%d",str,&op);
        if(str[0]=='Q') {
            printf("%d\n",sum(apple[op].r)-sum(apple[op].l-1));
        }
        else {
            a[apple[op].r]=1-a[apple[op].r];
            change(apple[op].r);
        }
    }
    return 0;
}

你可能感兴趣的:(树状数组)