首页 > 其他分享 >树上启发式合并

树上启发式合并

时间:2022-10-07 21:33:51浏览次数:73  
标签:cnt 树上 int void 合并 fa 启发式 now sum

树上启发式合并,是在统计信息的复杂度较高,没有办法每个点开一个信息空间的时候,考虑将信息空间公用,同时尽量保持时空复杂度平衡的方法。

例题:

CF600E

给定一棵有根树,每个点有一个颜色。对于每一个点为根的子树,求子树内出现次数最多的颜色的和(可并列)。
\(n \le 10^5, c_i \le n\)

思路分析:

https://zhuanlan.zhihu.com/p/565967113

代码实现:
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define f(i, a, b) for(int i = (a); i <= (b); i++)
#define cl(i, n) i.clear(),i.resize(n);
#define endl '\n'
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> pii;
const int inf = 1e9;
int n; 
int hson[100010];
int c[100010];
vector<int> g[100010];
int sz[100010];
int ans[100010], maxt, cnt[100010];
void fhson(int now, int fa) {
    sz[now] = 1;
    int mx = 0;
    f(i, 0, (int)g[now].size() - 1) {
        if(g[now][i] != fa) {
            fhson(g[now][i], now);
            sz[now] += sz[g[now][i]];
            if(sz[g[now][i]] > mx) {
                mx = sz[g[now][i]];
                hson[now] = g[now][i];
            }
        }
    }
}
int sum = 0;
void add(int now) {
    cnt[c[now]]++;
    if(cnt[c[now]] > maxt) {
        maxt = cnt[c[now]];
        sum = c[now];
    }
    else if(cnt[c[now]] == maxt){
        sum += c[now];
    }
}
void del(int now) {
    --cnt[c[now]];
    sum = 0; maxt = 0;
}
void asubtree(int now, int fa) {
    add(now);
    f(i, 0, (int)g[now].size()- 1) {
        if(g[now][i] != fa) asubtree(g[now][i], now);
    }
    return;
}
void dsubtree(int now, int fa) {
    del(now);
    f(i, 0, (int)g[now].size()- 1) {
        if(g[now][i] != fa) dsubtree(g[now][i], now);
    }
    return;    
}
void dfs(int now, int fa, bool keep) {
    f(i, 0, (int)g[now].size()- 1) {
        if(g[now][i] == fa ) continue;
        if(g[now][i] == hson[now]) continue;
        dfs(g[now][i], now, 0);
    }
    if(hson[now])dfs(hson[now], now, 1);
    add(now);
    f(i, 0, (int) g[now].size() - 1) {
        if(g[now][i] == fa ) continue;
        if(g[now][i] == hson[now]) continue;
        asubtree(g[now][i], now);        
    }
    ans[now] = sum;
    if(!keep) {
        dsubtree(now, fa);

    }
}
signed main() {
    ios::sync_with_stdio(0);
    cin.tie(NULL);
    cout.tie(NULL);
    time_t start = clock();
    //think twice,code once.
    //think once,debug forever.
    cin >> n;
    f(i, 1, n) {
        cin >> c[i];
    }
    f(i, 1, n - 1) {
        int u, v; cin >> u >> v;
        g[u].push_back(v);g[v].push_back(u);
    }
    fhson(1, 0);
    dfs(1, 0, 0);
    f(i,1 ,n) cout << ans[i] << " ";
    time_t finish = clock();
    //cout << "time used:" << (finish-start) * 1.0 / CLOCKS_PER_SEC <<"s"<< endl;
    return 0;
}

细节:

  • 分析一下发现 del 函数一旦运行,一定是把整个信息删空了。这时只需要直接把 \(sum\) 和 \(maxt\) 直接初始化即可。

标签:cnt,树上,int,void,合并,fa,启发式,now,sum
From: https://www.cnblogs.com/Zeardoe/p/16767118.html

相关文章

  • union合并查询结果集
    案例:查询工作岗位是MANAGER和SALESMAN的员工selectename,jobfromempwherejob='MANAGER'orjob='SALESMAN';selectename,jobfromempwherejobin('MANAG......
  • sql表合并查询
    使用sql语句将数据库中的一个表里的数据导入到另一个表中两个表,表1表2如果要将表1的数据并入表2用以下语句即可insertinto表2(字段1,字段2)select字段1,字段2fr......
  • 【算法-简单01】合并2个有序数列
    合并2个有序数列结果:时间复杂度:O(N)空间复杂度:O(N)比较抽象的点结论:Node对象有3个属性:Node本身、val,以及Node.nextNode本身判空,结合while来进行遍历查询val......
  • 合并链表
    ListNode*mergeTwoLists(ListNode*l1,ListNode*l2){if(l1==NULL){if(l2==NULL){returnNULL;}els......
  • P2680 [NOIP2015 提高组] 运输计划 (树上差分-边差分)
    P2680题目的大意就是走完m条路径所需要的最短时间(边权是时间),其中我们可以把一条边的权值变成0(也就是题目所说的虫洞)。可以考虑二分答案x,找到一条边,使得所有大于x的路径......
  • 合并10/5
    #include<stdio.h>#include<stdlib.h>#defineMAXSIZE20typedefstructLNODE{charlist[MAXSIZE];intlistlen;//表的当前长度}*List,L;voidinit(ListPtrl,inta......
  • 图论专题-学习笔记:树上启发式合并(dsu on tree)
    目录1.前言2.详解3.总结1.前言树上启发式合并(dsuontree),是一种类似于启发式合并的方式解决关于部分子树内问题的算法,一般都是什么子树内颜色个数等等的。前置知识:......
  • 做题记录整理数据结构1 P6033. [NOIP2004 提高组] 合并果子 加强版(2022/10/3)
    P6033.[NOIP2004提高组]合并果子加强版老题新做型里面最妙的就是用两个队列来代替一个堆,和蚯蚓那道题有异曲同工之妙#include<bits/stdc++.h>#definefor1(i,a,b)......
  • 「CF1455G」Forbidden Value 题解 (DP,线段树合并)
    题目简介已知初始值\(x=0\),给定下面\(2\)种命令:set\(y\)\(v\),令\(x=y\),或花费\(v\)元钱删除该命令;if\(y\)...end,如果\(x==y\),执行if...end中的命令,否则跳......
  • 合并两个list对象集合并排序
    List对象合并后进行排序业务场景用户相关字段数量较多时,会进行分表,用相同的id进行关联,而后进行数据查询时,需要将两张或者多张表的数据进行拼接思路:将其中一个list1转换为map......