• 喵哈哈村的卢西奥


    为了拯救喵哈哈村,这个世界必须要存在英雄。

    一名叫做卢西奥的英雄站了出来!他现在面临一个难题:

    他被要求将一棵树拆成3份,使得每一份中所有节点的权值和相等。

    他希望知道,对于一棵给定的有根树,在选取其中2个非根节点并将它们与它们的父亲节点分开后,所形成的三棵子树的节点权值之和能够两两相等的方案有多少种。

    两种方案被看做不同的方案,当且仅当形成方案的2个节点不完全相同。

    每个输入文件包含多组输入,在输入的第一行为一个整数T,表示数据的组数。

    每组输入的第一行为一个整数N,表示给出的这棵树的节点数。

    接下来N行,依次描述结点1~N,其中第i行为两个整数Vi和Pi,分别描述这个节点的权值和其父亲节点的编号。

    父亲节点编号为0的节点为这棵树的根节点。

    满足3<=N<=100000, |Vi|<=100, T<=10

    对于每组输入,输出一行Ans,表示方案的数量。


    2
    3
    1 0
    1 1
    1 2
    4
    1 0
    1 1
    1 2
    1 3
    1
    0
    题解

    两种情况:

    第一种情况,有两个是子树,这个东西用启发式合并/dp去维护一下当前sz[x]=all/3的个数就好了。

    第二种情况,只有一个是子树,那么第二段显然是包含了第一段的,那么就存在一个的size=2all/3,一个sz=all/3的情况,统计一下就好了。

    dfs处理一下就好了,具体看代码:

    #include<bits/stdc++.h>
    // #include <unordered_set>
    
    using namespace std;
    
    #define FF first
    #define SS second
    #define MP make_pair
    #define PB push_back
    #define lson rt << 1, l, mid
    #define rson rt << 1 | 1, mid + 1, r
    #define FOR(i, n, m) for(int i = n; i <= m; i++)
    #define REP(i, n, m) for(int i = n; i >= m; i--)
    #define ll long long
    
    typedef long long LL;
    typedef pair<int,int> PII;
    typedef pair<LL, LL> PLL;
    typedef unsigned long long ULL;
    
    /****************************define***************************************/
    const int mod = 1e9 + 7;
    const int maxn = 100010;
    
    
    int n;
    int v[maxn], sz[maxn], p[maxn];
    vector<int> nd[maxn];
    int s;
    int cn = 0, cn2 = 0;
    ll ans = 0;
    
    void Dfs_sz(int u){
            sz[u] += v[u];
            int t = nd[u].size();
            FOR(i, 0, t-1) {
                Dfs_sz(nd[u][i]);
                sz[u] += sz[nd[u][i]];
                }
            }
    void Dfs(int u){
            //printf("node %d. ans %d. cn %d. cn2 %d. sz %d
    ", u, ans, cn, cn2, sz[u]);
            if(sz[u] == s/3) {
                ans += cn + cn2;
                //printf("node %d. ans %d
    ", u, ans);
                }
            if(p[u] != 0 && sz[u] == s*2/3) cn2++;
            int t = nd[u].size();
            FOR(i, 0, t-1){
                Dfs(nd[u][i]);
                }
            if(sz[u] == s/3) cn++;
            if(p[u] != 0 && sz[u] == s*2/3) cn2--;
            }
    
    int main(){
            int t;
            cin >> t;
            while(t--){
                cn = 0, cn2 = 0;
                s = 0, ans = 0;
                FOR(i, 0, maxn-1) nd[i].clear();
                memset(sz, 0, sizeof(sz));
    
                int n, root=-1;
                cin >> n;
                FOR(i, 1, n) {
                    cin >> v[i] >> p[i];
                    s += v[i];
                    nd[p[i]].PB(i);
                    if(p[i] == 0) root=i;
                    }
                if(s % 3 != 0) cout << 0 << endl;
                else{
                    Dfs_sz(root);
                    Dfs(root);
                    printf("%lld
    ", ans);
                    }
                }
            return 0;
            }
     
  • 相关阅读:
    HDU 5919 分块做法
    HDU 3333 分块求区间不同数和
    CF 333E 计算几何+bitset优化
    hdu 1043 八数码--打表
    hdu 1043 八数码问题-A*搜索
    hdu 5919 主席树
    hiho1388 FFT/NTT
    HDU 5869区间CGD不同种类数---树状数组+map统计区间不同种类数(离线)
    HDU 5875 二分+st表
    HDU 5898 基础数位DP
  • 原文地址:https://www.cnblogs.com/gfdybz/p/6558850.html
Copyright © 2020-2023  润新知