• 模板【树上合并式启发】


    PART1(算法思想简介)

    1.实现

    Q:既然轻儿子会被清除掉,还访问它干啥呢 ?好疑惑啊

    A:因为这种题的特性是“根和它的子节点的ans依据为包含关系,但是每个节点依旧需要根据其相应的所有依据来作出结论”,所以先访问一次轻子节点是为了得到子节点的ans,而 之后的访问 就和之前 的访问目的(为了得到根的ans)操作 都不一样了,前一次相当于统计数组是tot[v][1~color],之后一次相当于tot[u][1~color],只是数组大小限制 ,不得不使得  u,v共用一个 tot[1~color]

    Q:既然这样 ,那先统计重孩子,再统计root,在统计轻子结点可以吗?毕竟root的依据又不依赖轻子节点的依据。

    A:不可行,通过“对算法的感悟-从底层思考其起”,就会发现访问重儿子然后统计整棵树后,这课树的所有信息都应到保留下来给它的fa(当它是fa的重孩子时就要留下),所以程序到这里就应当结束了,可是还有轻子结点需要搞,显然是不对的,所以像一个点的轻子结点的数据是肯定不需要保留了(设定是这样,见Q1知道它必定被清楚),先做完,因为它的重孩子做完还有东西要留给它的fa

    2.时间复杂度

    3.特别优势

    4.适用情况

    5.需要注意的点

    1.SumDfs的时候只有当前计算的结点的重儿子不重复算,其它轻儿子的各种儿子还是要算啊!!所以SumDfs(u, fa, rootMaxSon)要有rootMaxSon不变

    2.遇见 fa必须写成 continue,否则大括号 必须  把  所有人都 框进去,否则你真的 要仔细考虑 了,还是用continue吧

    3.图论题也能要用longlong

    6.函数、变量名的解释+英文

    dsu on tree(树上合并式启发)(某个毒瘤@noip 说这个是静态链分治)

    maxSon要存在才继续dfs啊

    7.dalao分析

    基础知识(看不懂)

    dalao总结

    第一个例题(关联了好多题)

    PART2(算法各种类型(并附上代码))

     这是一个例题的代码,不过也算模板了(几百年没遇到要开Longlong的图论题了)

    #include<cstdio>
    #include<cmath>
    #include<algorithm>
    #include<set>
    #include<map>
    #include<cstring>
    #include<string>
    #include<vector>
    #include<queue>
    #include<iomanip>
    #include<iostream>#include<stack>
    using namespace std;
    #define inf 0x3f3f3f3f
    #define  ll  long long
    #define re register int
    const int N = 1e5+10;
    const int M = 2e5+10;
    inline int read()
    {
        int x=0;
        char ch=getchar();
        while(!isdigit(ch))
            ch=getchar();
        while(isdigit(ch))
            x=(x<<1)+(x<<3)+ch-'0',ch=getchar();
        return x;
    }
    //与边相关
    struct edge
    {
        int v, next, w;
    } e[M];
    int p[N], eid;
    inline void InitEdge()
    {
        memset(p, -1, sizeof(p));
        eid = 0;
    }
    inline void Insert(int u, int v, ll w = 0)
    {
        e[eid].next = p[u];
        e[eid].v = v;
        e[eid].w = w;
        p[u] = eid++;
    }
    //建图
    ll color[N];
    inline void In(int &n)
    {
        n = read();
        for(re i = 1; i <= n; i++)
            color[i] = read();
        int u, v;
        for(re i = 1; i <  n; i++)
        {
            u = read();
            v = read();
            Insert(u, v);
            Insert(v, u);
        }
    }
    //重链分治
    int size[N];//子树大小
    int maxSon[N];
    void FindMaxSonDfs(int u,int fa)
    {
        size[u] = 1;
        maxSon[u] = 0;
        for(re i = p[u]; ~i; i = e[i].next)
        {
            int v = e[i].v;
            if(v == fa) continue;
            FindMaxSonDfs(v, u);
            size[u] += size[v];
            if(size[maxSon[u]] < size[v])
                maxSon[u] =  v;
        }
    }
    //树上合并式启发
    ll ans[N];
    ll cnt[N];//记录每种颜色出现的次数
    ll maxCnt;//最大的次数
    ll sumOfMax;//最大颜色的答案
    void SumDfs(int u, int fa, int rootMaxSon)
    {
        cnt[color[u]]++;
        if(cnt[color[u]] > maxCnt)
        {
            maxCnt = cnt[color[u]];
            sumOfMax = color[u];
        }
        else if(cnt[color[u]] ==  maxCnt)
            sumOfMax += color[u];
        for(re i = p[u]; ~i; i = e[i].next)
        {
            int v = e[i].v;
            if(v == fa  ||  v == rootMaxSon)
                continue;
            SumDfs(v, u, rootMaxSon);
        }
    }
    inline void InitCnt(int u,int fa) //暴力遍历后清空
    {
        cnt[color[u]]--;
        for(re i = p[u]; ~i; i = e[i].next)
        {
            int v = e[i].v;
            if(v == fa)
                continue;
            InitCnt(v, u);
        }
    }
    void Dfs(int u, int fa)
    {
        for(re i = p[u]; ~i; i = e[i].next)
        {
            int v = e[i].v;
            if(v == fa  || v == maxSon[u])
                continue;
            Dfs(v, u);
            InitCnt(v, u);
            maxCnt = sumOfMax = 0;
        }
        if(maxSon[u])
        {
            Dfs(maxSon[u], u);
        }
        SumDfs(u, fa, maxSon[u]);
        ans[u] = sumOfMax;
    }
    int main()
    {
        //freopen("in.txt","r", stdin);
        //freopen("out.txt","w", stdout);
        //ios::sync_with_stdio(false);
        InitEdge();
        int n;
        In(n);
        FindMaxSonDfs(1, -1);
        Dfs(1, -1);
        for(re i = 1; i <=  n; i++)
            printf("%lld ", ans[i]);
        return 0;
    }
    View Code

    PART3(算法的延伸应用)

    PART4(对算法深度的理解)

     DFS在思考时要从最底层想起(不会再继续递归下去的那一层)

    PART5(与其相关的有趣题目)

     

  • 相关阅读:
    Java实现 LeetCode 130 被围绕的区域
    Java实现 LeetCode 130 被围绕的区域
    Java实现 LeetCode 130 被围绕的区域
    win32创建控件的一些问题
    win32 sdk绘制ListBox控件
    VC++ WIN32 sdk实现按钮自绘详解 之二.
    win32 sdk 列表视图控件绘制
    win32 sdk树形控件的项拖拽实现
    MFC 用gdi绘制填充多边形区域
    vc 按钮自绘
  • 原文地址:https://www.cnblogs.com/bear-xin/p/14974111.html
Copyright © 2020-2023  润新知