E - Apple Tree(DFS序,树状数组)

E - Apple Tree

POJ - 3321

题意:

​ 一颗苹果树,刚开始所有节点都有苹果,有以下两种操作,一种是改变一个节点的状态(有苹果就取走,没苹果就产生一个),一种是询问一个点的子树(包括节点自己)一共有多少个苹果,对于每次询问输出结果

分析:

重新DFS序给节点标号,那么没个节点的子孙就对应一个连续的区间。那么修改点的状态相当于单点修改,查询操作相当于区间求和,树状数组和线段树都可以写。

注:POJ存树图用vector超时

#include
#include
#include
#include
#include
#define mset(a,b) memset(a,b,sizeof(a))
using namespace std;
typedef long long ll;
const ll MAXN=1e5+20;
const ll MAX=100000;
ll DS[MAXN],L[MAXN],R[MAXN];//顶点u对应的区间为[L,R],u的虚拟节点为DS[u]
ll book[MAXN],tot,ecnt;
ll bt[MAXN],sw[MAXN];
int head[MAXN];
struct Edge{
 int v,to;
}edge[MAXN<<1];
void addEdge(int u,int v,int ed)
{
    edge[ed].v=v;
    edge[ed].to=head[u];
    head[u]=ed;
}
void dfs(ll u)
{
    tot++,book[u]=1;
    DS[u]=tot,L[u]=tot;
    int to=head[u];
    while(to!=-1)
    {
        int v=edge[to].v;
        to=edge[to].to;
        if(book[v]) continue;
        dfs(v);
    }
    R[u]=tot;
}
/*
重现构造搜索序列
*/
ll lowbit(ll k)
{
    return k&-k;
}
void modify(ll k,ll val)
{
    while(k<=MAX){
        bt[k]+=val;
        k+=lowbit(k);
    }
}
ll getsum(ll k)
{
    ll ans=0;
    while(k>0)
    {
        ans+=bt[k];
        k-=lowbit(k);
    }
    return ans;
}
char s[10];
int main(){
    ll n;
    scanf("%lld",&n);
    ecnt=0ll;
    mset(head,-1);
    for(ll i=0;i<n-1;++i){
        ll u,v;
        scanf("%lld%lld",&u,&v);
        addEdge(u,v,ecnt++);
        addEdge(v,u,ecnt++);
    }
    tot=0;
    dfs(1);
    for(ll i=1;i<=n;++i)
        modify(i,1);
    ll q;
    scanf("%lld",&q);
    while(q--)
    {
        scanf("%s",s);
        if(s[0]=='Q'){
            ll u;
            scanf("%lld",&u);
            printf("%lld\n",getsum(R[u])-getsum(L[u]-1));
        }
        else{
            ll u;
            scanf("%lld",&u);
            if(sw[u]==1){
                sw[u]=0;
                modify(DS[u],1);
            }
            else{
                sw[u]=1;
                modify(DS[u],-1);
            }
        }
    }
    return 0;
}

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