zoukankan      html  css  js  c++  java
  • POJ 3321 Apple Tree 树状数组 第一题

    第一次做树状数组,这个东西还是蛮神奇的,通过一个简单的C数组就可以表示出整个序列的值,并且可以用logN的复杂度进行改值与求和。

    这道题目我根本不知道怎么和树状数组扯上的关系,刚开始我想直接按图来遍历来做,后来用树状数组做完都跑了600+MS,那样估计是TLE了。

    做法就是用DFS把整个图重建一遍,代号小的点在叶子,代号大的点为根。记录每个根的起始点号为 idl,根点号为 idh,则求某个根的苹果和就直接调用树状数组的sum即可。

    不过前提是要建好树,我一开始不明白为什么要建一颗标准树,即就是按1 2 3 4。。。。,每个点有一个苹果的递增的标准树,因为整个图并不是按这个标准来建得,2号点C值为1号和2号的和,但实际的树可能1号和2号都是叶子啊。。。。后来想清楚了,每次求和都是建立在某个根上,而这个根和它的所有孩子是符合标准树状数组的。

    #include <cstdio>
    #include <cstring>
    #define N 100010
    using namespace std;
    int u[N],v[N],nt[N],ft[N],idh[N],idl[N],cnt,isapple[N],c[N];
    void add(int a,int b)
    {
        u[cnt]=a;
        v[cnt]=b;
        nt[cnt]=ft[a];
        ft[a]=cnt++;
    }
    int n;
    void dfs(int x)
    {
        idl[x]=cnt;
        if (ft[x]==-1)
        {
            idh[x]=cnt++;
            return;
        }
        for (int i=ft[x];i>=0;i=nt[i])
        {
            int nx=v[i];
            dfs(nx);
        }
        idh[x]=cnt++;
    }
    int lowbit(int x)
    {
        return x & (-x);
    }
    void update(int x)
    {
        int d;
        if (isapple[x])
        {
            d=-1;
            isapple[x]^=1;
        }
        else
        {
            d=1;
            isapple[x]^=1;
        }
        while (x<=n)
        {
            c[x]+=d;
            x+=lowbit(x);
        }
    }
    int getsum(int x)
    {
        int ret=0;
        while (x>0)
        {
            ret+=c[x];
            x-=lowbit(x);
        }
        return ret;
    }
    int main()
    {
        int m;
        while (scanf("%d",&n)!=EOF)
        {
            cnt=0;
            int a,b;
            memset(ft,-1,sizeof ft);
            memset(c,0,sizeof c);
            for (int i=1;i<n;i++)
            {
                scanf("%d%d",&a,&b);
                add(a,b);
            }
            cnt=1;
            dfs(1);
            for (int i=1;i<=n;i++)
            {
                isapple[i]=0;
                update(i);
            }
            //puts("pp");
            scanf("%d",&m);
            char ch[2];
            int nt;
            while (m--)
            {
              // puts("pass");
                scanf("%s%d",ch,&nt);
                //puts(ch);
                if (ch[0]=='Q')
                {
                    int ans=getsum(idh[nt])-getsum(idl[nt]-1);//求结果的时候就求根的sum以及最小叶子的前一点,相减就是该棵树的和,就跟前缀和一样的原理
                    printf("%d
    ",ans);
                }
                else
                {
                    update(idh[nt]);
                }
                //getchar();
            }
        }
        return 0;
    }
  • 相关阅读:
    [笔记]流行数据库SQL差异分析之“不从实体表中取得数据”
    如何评价架构的优劣(转)
    Entity Framework 学习总结之一:ADO.NET 实体框架概述
    [笔记]流行数据库SQL差异分析之“自动增长字段”
    Entity Framework 学习总结之十:加载相关对象
    Entity Framework 学习总结之九:LinqToEntities
    Entity Framework 学习总结之二:数据访问区别
    3、网站前端优化11条笔记汇总
    Entity Framework 学习总结之八:EntitySQL 复杂查询及函数
    Entity Framework 学习总结之七:EntitySQL 基本查询
  • 原文地址:https://www.cnblogs.com/kkrisen/p/3588641.html
Copyright © 2011-2022 走看看