• FZU 2176 easy problem (DFS序+树状数组)


    对于一颗树,dfs遍历为每个节点标号,在进入一个树是标号和在遍历完这个树的子树后标号,那么子树所有的标号都在这两个数之间,是一个连续的区间。(好神奇~~~)

    这样每次操作一个结点的子树时,在每个点的开始结束两个点标记一下就可以,用树状数组求前缀和就可知道每个点的值。

    这道题虽然很麻烦(dep[y]-dep[x])%k 。但是注意到K很小(1<=k<=5),可以维护k个树状数组。

    提交时编译器选GUN C++迷之RE。。。换Visual C++

    #include <cstdio>
    #include <cstring>
    #include <vector>
    #include <algorithm>
    #define clr(x,c) memset(x,c,sizeof(x))
    using namespace std;
    typedef long long ll;
    
    const int N = 50005;
    
    vector<int> g[N];
    vector<int> lev[5];
    ll bit[5][N];
    int d[N], l[N], r[N];
    int n, m, k;
    int cnt;
    
    
    void dfs(int u, int fa, int dep)
    {
        d[u] = dep;
        l[u] = ++cnt;
        lev[dep%k].push_back(l[u]);
        for (unsigned i = 0; i < g[u].size(); ++i) {
            int v = g[u][i];
            if (v == fa) continue;
            dfs(v, u, dep+1);
        }
        r[u] = cnt;
    }
    
    void init()
    {
        for (int i = 0; i <= n; ++i) g[i].clear();
        for (int i = 0; i < k; ++i) lev[i].clear();
        clr(bit, 0); clr(l, 0); clr(r, 0); clr(d, 0);
        cnt = 0;
    }
    
    int lb(int j, int x)
    {
        return lower_bound(lev[j].begin(), lev[j].end(), x) - lev[j].begin() + 1;
    }
    
    int lowbit(int x) { return x & -x; }
    
    void add(int j, int pos, int val)
    {
        while (pos <= lev[j].size() ) {
            bit[j][pos] += val;
            pos += lowbit(pos);
        }
    }
    
    ll sum(int j, int pos)
    {
        ll ans = 0;
        while (pos) {
            ans += bit[j][pos];
            pos -= lowbit(pos);
        }
        return ans;
    }
    
    int main()
    {
        int t;
        int cas = 0;
        scanf("%d", &t);
        while (t--) {
            printf("Case#%d:
    ", ++cas);
            scanf("%d%d%d", &n, &m, &k);
            init();
            int u, v;
            for (int i = 1; i < n; ++i) {
                scanf("%d%d", &u, &v);
                g[u].push_back(v);
                g[v].push_back(u);
            }
            dfs(1, 0, 0);
            while (m--) {
                int ch, x, v;
                scanf("%d%d", &ch, &x);
    
                if (ch == 1) {
                    scanf("%d", &v);
                    for (int i = 0; i < k; ++i) {
                        int j = (i + d[x]) % k;
                        int ls = lb(j, l[x]), rs = lb(j, r[x]+1);
                        add(j, ls, (i + 1) * v);
                        add(j, rs, (-1 - i) * v);
                    }
                } else {
                    int j = d[x] % k;
                    int s = lb(j, l[x]);
                    printf("%lld
    ", sum(j, s));
                }
            }
        }
        return 0;
    }
  • 相关阅读:
    用Python随机生成一个六位验证码(验证码由数字和字母组成(大小写字母))
    0.4 uwsgi和nginx部署常见问题及解决
    Android小笔记
    Android之背景透明度
    Android开发中的错误总结
    Android “再按一次退出“
    java数组对象的复制
    Android之OpenCv
    学习资料
    Android常用正则表达式
  • 原文地址:https://www.cnblogs.com/wenruo/p/5452775.html
Copyright © 2020-2023  润新知