zoukankan      html  css  js  c++  java
  • [hdu5593 ZYB's Tree] 树上统计

    题意:给1棵N(≤500,000)个节点的树,每条边边权为1,求距离每个点距离不超过K(K≤10)的点的个数的xor和。

    思路:由于K很小,可以考虑把距离作为状态的一部分,然后研究父子之间状态的联系。令ans[i][j]表示与i的距离为j的点的个数,那么ans[i][j]由两部分构成,一部分来源于子树,一部分来源于父亲,那么令f[i][j]表示从子树来的答案,g[i][j]表示从父亲来的答案,son(i)表示i的儿子,fa(i)表示i的父亲,则有:

     ans[i][j] = f[i][j] + g[i][j]

    f[i][j] = ∑f[son(i)][j-1]

    g[i][j] = ans[fa(i)][j-1] - f[i][j-2]

    具体做法是:先自底向上求解f数组,这里可以利用队列按拓扑序依次访问每个点,然后自顶向下求g数组,这时只要在上一步的队列里面逆着扫一遍就行了。由于没有递归,速度还是非常快的,把上面的g和ans省掉后,以200ms的速度排到了rank1,小小激动了一下=.=

    #include <bits/stdc++.h>
    using namespace std;
    #ifndef ONLINE_JUDGE
        #include "local.h"
    #endif
    
    #define pb(x) push_back(x)
    #define mp(x, y) make_pair(x, y)
    #define all(a) (a).begin(), (a).end()
    #define watch(ele) cout << ele << endl;
    #define mset(a, x) memset(a, x, sizeof(a))
    #define mcpy(a, b) memcpy(a, b, sizeof(b))
    #define up(a, b) for (int a = 0; a < b; a ++)
    #define up1(a, b) for (int a = 1; a <= b; a ++)
    #define down1(a, b) for (int a = b; a >= 1; a --)
    #define rep(i, a, b) for (int i = a; i <= b; i ++)
    #define rrep(i, a, b) for (int i = a; i >= b; i --)
    #define down(a, b) for (int a = b - 1; a >= 0; a --)
    #define cas() int T, cas = 0; cin >> T; while (T --)
    #define printCas(ch) printf("Case #%d:%c", ++ cas, ch)
    
    typedef long long ll;
    typedef pair<int, int> pii;
    
    template<typename T>bool umax(T&a, const T&b){return a<b?(a=b,true):false;}
    template<typename T>bool umin(T&a, const T&b){return b<a?(a=b,true):false;}
    
    const int N = 5e5 + 7;
    
    int n, k, a, b;
    int din[N], fa[N], f[N][11];
    
    void getData() {
        mset(din, 0);
        fa[1] = 0;
        rep(i, 2, n) {
            int f = ((ll)a * i + b) % (i - 1) + 1;
            din[f] ++;
            fa[i] = f;
        }
    }
    int Q[N], head, tail;
    void work() {
        head = tail = 0;
        mset(f, 0);
        up1(i, n) if (din[i] == 0) Q[tail ++] = i;
        up1(i, n) f[i][0] = 1;
        while (head < tail) {
            int node = Q[head ++];
            up(i, k) f[fa[node]][i + 1] += f[node][i];
            if (-- din[fa[node]] == 0) Q[tail ++] = fa[node];
        }
        int apple = 0;
        rrep(i, tail - 1, 0) {
            int node = Q[i];
            if (fa[node]) rrep(j, k, 1) f[node][j] += f[fa[node]][j - 1] - (j >= 2?f[node][j - 2] : 0);
            int buf = 0;
            rep(j, 0, k) buf += f[node][j];
            apple ^= buf;
        }
        cout << apple << endl;
    }
    int main() {
    #ifndef ONLINE_JUDGE
        freopen("in.txt", "r", stdin);
        //freopen("out.txt", "w", stdout);
    #endif // ONLINE_JUDGE
        cas() {
            cin >> n >> k >> a >> b;
            getData();
            work();
        }
        return 0;
    }
    

      

  • 相关阅读:
    求树中两个节点的最低公共祖先
    [2014校招笔试]判断单链表是否有环?
    二叉树的遍历
    求所有划分集合
    用rand5()生成rand(n)
    由等概率生成的0和1构建rand()函数
    等概率生成0和1
    求输出和为n的所有连续自然数序列
    求正整数n的所有因子
    css 2D转换总结
  • 原文地址:https://www.cnblogs.com/jklongint/p/5022724.html
Copyright © 2011-2022 走看看