zoukankan      html  css  js  c++  java
  • 杭电 3887 Counting Offspring

    根据上篇翻译的文章以及很多个帖子,都讲述了树状数组最基本的功能就是tree[i]保存的是位置i左边小于等于a[i]的数的个数.

    这样也就可以解释代码中为什么有f[i]=getsum(sd[i-1])-getsum(st[i]))/2。因为getsum保存的就是左边比i小的数,注意因为序列是通过dfs求出的,因而每个节点都有进入和退出过程,也就是每个节点都出现了2次,比如说对于数4来说,有4个节点,假设3为顶点,边的关系是3-2-1,3-2-4,那么dfs扫描出的序列就是3,2,1,1,4,4,2,3.所以求出的最终结果就需要除以2,因为每个数字都出现了2次。

    至于为什么是从n-->1,我也纠结了半天,后来总算是YY出了一点思路【也可能不对】,因为已经将tree初始过了,考虑最原始的BIT,我们是一边遍历原始数组,一边getsum,一边update树,更新时,tree[i]+=1,这里提前将tree update过了,那么只能从后向前走,update(-1)了。假定最后一个点是n,那么在考虑其他节点的时候是不需要考虑这个点的,因为任何一个点都比最后这个点小,所以。。。update的时候是(-1)。

    代码中注释的部分是原作者的,为了证实一下我自己YY出的结果是否正确,我测试了一下,果然A掉了。所以我的想法应该是对的,如果从头开始的话,需要从头遍历数组,得结果的时候需要两次update(1),这样的话仅仅需要从1-->就可以了。

    代码如下:


    #pragma comment(linker,"/STACK:100000000,100000000")
    #include <iostream>
    #include <cstdio>
    #include <algorithm>
    #include <vector>
    #include <cstring>
    using namespace std;
    
    const int maxn=100005;
    vector<int>vt[maxn];
    int bit[2*maxn];
    int que[2*maxn];
    int st[maxn];
    int sd[maxn];
    int f[maxn];
    int n, rt, num;
    
    void dfs(int u, int fa)
    {
        que[++num]=u;
        for(int i=0; i<vt[u].size(); i++)
        {
            int v=vt[u][i];
            if(v==fa) continue;
            dfs(v,u);
        }
        que[++num]=u;
    }
    
    int lowbit(int x)
    {
        return x&(-x);
    }
    
    void update(int x, int val)
    {
        while(x<=num)
        {
            bit[x]+=val;
            x+=lowbit(x);
        }
    }
    
    int getsum(int x)
    {
        int ans=0;
        while(x>0)
        {
            ans+=bit[x];
            x-=lowbit(x);
        }
        return ans;
    }
    
    int main()
    {
    	//int a=4,b=3;
    	//printf("%d",a|b);
        while(~scanf("%d%d",&n,&rt),n+rt)
        {
            for(int i=0; i<=n; i++)
                vt[i].clear();
            for(int i=1; i<n; i++)
            {
                int x, y;
                scanf("%d%d",&x,&y);
                vt[x].push_back(y);
                vt[y].push_back(x);
            }
            fill(st+1,st+1+n,0);
            num=0;
            dfs(rt,-1);
    		//每个节点开始和结束的位置
            for(int i=1; i<=num; i++)
            {
                if(!st[que[i]])
    				st[que[i]]=i;
                else 
    				sd[que[i]]=i;
            }
            memset(bit,0,sizeof(bit));
    		/*
            for(int i=1; i<=num; i++)
                update(i,1);
            for(int i=n; i>=1; i--)
            {
                f[i]=(getsum(sd[i]-1)-getsum(st[i]))/2;
                update(st[i],-1);
                update(sd[i],-1);
            }*/
    		for(int i=1;i<=n;i++)//这里是测试从1-->n的,注意对比
    		{
    			update(st[i],1);
    			update(sd[i],1);
    			f[i]=(getsum(sd[i]-1)-getsum(st[i]))/2;
    		}
            printf("%d",f[1]);
            for(int i=2; i<=n; i++)
                printf(" %d",f[i]);
            puts("");
        }
        return 0;
    }


  • 相关阅读:
    文件上传Web小案例
    加密方法(MD5加密)
    解决中文乱码(不可能解决不了)
    jquery的一些常见使用方法
    Ajax的作用
    日期时间格式的转换
    前端点击复制内容
    uniapp 移动端防止点击事件穿透
    getCurrentPages 获取当前网页完整的URL
    关闭微信浏览器网页
  • 原文地址:https://www.cnblogs.com/suncoolcat/p/3339410.html
Copyright © 2011-2022 走看看