• poj3321 dfs序+树状数组单点更新 好题!


    当初听郭炜老师讲时不是很懂,几个月内每次复习树状数组必看的题

    树的dfs序映射在树状数组上进行单点修改,区间查询。

    /*
    树状数组:
    lowbit[i] = i&-i
    C[i] = a[i-lowbit[i]+1]+...+a[i]
    
    求和: 
        设sum[k] = a[1]+a[2]+...+a[k]
        则a[i]+a[i+1]+...+a[j] = sum[j]-sum[i-1]
        在树状数组上:sum[k] = C[n1]+C[n2]+...+C[k]
            n1 = n2-lowbit[n2]... >0 
    
    更新:
        如果a[i]更新了,则以下几项也要更新    
        C[n1], C[n2], ... C[nm]
            n1 = i, n2 = n1+lowbit[n1].. nm<=N  
    
    建树:O(N)
        C[k] = sum[k]-sum[k-lowbit[k]] 
    
    poj3321
    树状数组:单点更新
    书上长满了苹果,每一个节点有长苹果和不长两种状态
    操作1:改变树枝上有无苹果的状态
    操作2:询问某一树枝节点以下的所有的苹果有多少
    
    做一次dfs,几下每个节点的开始时间Start[i]和结束时间End[i]
    对于i节点的所有子孙的开始时间和结束时间都应该位于Start[i]和End[i]之间 
    C[i]是树状数组节点对应的苹果数 
     
    然后用树状数组C统计Start[i]到End[i]之间的附加苹果总数
    树状数组统计区间可以用Sum(End[i])-Sum(Start[i]-1)来计算 
    */
    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #include<vector>
    #define MAXN 220000 
    using namespace std;
    int C[MAXN];
    vector<vector<int> > G(MAXN/2);//
    int Lowbit[MAXN];
    int Start[MAXN];
    int End[MAXN];
    bool HasApple[MAXN/2];
    int nCount;
    //dfs搜索出所有状态 
    void dfs(int v){
        Start[v] = ++nCount;
        for (int i = 0; i != G[v].size(); i++)
            dfs(G[v][i]);
        End[v] = ++nCount;
    }
    //求1-p的和 
    int QuerySum(int p){
        int nSum = 0;
        while(p > 0){
            nSum += C[p];
            p -= Lowbit[p];
        }
        return nSum;
    }
    //修改节点p的值 
    void Modify(int p, int val){
        while(p <= nCount){
            C[p] += val;
            p += Lowbit[p];
        }
    } 
    int main(){
        int n;
        scanf("%d", &n);
        int x, y;
        int i, j, k;
        for (i = 0; i < n-1; i++){
            int a, b;
            scanf("%d%d", &a, &b);
            G[a].push_back(b);
        }
        nCount = 0;
        dfs(1);//从根节点开始dfs
        
        //树状数组要处理的原石数组下标范围 
        for (i = 1; i <= nCount; i++)
            Lowbit[i] = i&(-i);
            
        for(i = 1; i <= n; i++)
            HasApple[i] = 1; 
        
        int m;
        //建树求C数组,即树状数组的节点值 
        for(i = 1; i <= nCount; i++)
            C[i] = i-(i-Lowbit[i]);
            //C[i] = Sum[i] - Sum[i-Lowbit[i]]; 
        
        scanf("%d", &m);
        for (int i = 0; i < m; i++){
            char cmd[10];
            int a;
            scanf("%s%d", cmd, &a);
            //改变某个节点上的苹果的状态 
            if (cmd[0] == 'C') {
                if(HasApple[a] == 1){
                    Modify(Start[a], -1);
                    Modify(End[a], -1);
                    HasApple[a] = 0; 
                } 
                else {
                    Modify(Start[a], 1);
                    Modify(End[a], 1);
                    HasApple[a] = 1;
                }
            }
            //查询某个节点上的苹果 
            else {
                int t1 = QuerySum(Start[a]-1);
                int t2 = QuerySum(End[a]);
                cout << (t2-t1)/2 << endl; 
            }
        } 
    }
  • 相关阅读:
    剑指offer字符串列表
    剑指offer数组3
    剑指offer数组2
    剑指offer数组1
    剑指offer数组列表
    tensorflow+ssd_mobilenet实现目标检测的训练
    Win7+keras+tensorflow使用YOLO-v3训练自己的数据集
    Java是如何实现跨平台的
    Xshell 、PuTTY 复制文件到Linux
    Asp.Net Core2.0在linux下发布
  • 原文地址:https://www.cnblogs.com/zsben991126/p/10085046.html
Copyright © 2020-2023  润新知