• 杭电 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;
    }


  • 相关阅读:
    Linux c 开发25 VScode C++ 运行中文乱码
    IEC104开发3 lib60870IEC 608705101 / 104 SOE
    Linux c 开发26 cmake生成项目
    STM32 例程7 STM32固件库方式 读取SHT20 温湿度
    基本电路学习1 12v转5V 电路
    github copilot 代码智能提示 AI代码提示
    Cesium polygon polyline entity label 贴地 点线面文本模型贴地 clampToGround 地面遮挡 地底遮挡 文字遮挡 道路遮挡 地形遮盖 地图遮盖
    UE4 HTTP REST 请求与高德天气预报接口 VaRest 插件
    UE4 蓝图截图 全屏截图 蓝图笔记截图 蓝图高清截图 蓝图保存插件 Blueprint Graph Screenshot(蓝图截图插件)
    window Carnac 实时显示键盘按键 桌面显示按钮 虚拟键盘 演示键盘 直播教学键盘
  • 原文地址:https://www.cnblogs.com/suncoolcat/p/3339410.html
Copyright © 2020-2023  润新知