zoukankan      html  css  js  c++  java
  • CF 600E 树上启发式合并

    DUS on tree

    难得都不会,会的都是板子,可悲,可悲

    题意:略

    先想一个O(n^2)的写法,然后想办法去掉重复计算。究竟哪里重复 了呢?

    假设p是x的儿子,p有很多个。每次计算答案的时候,如果“重儿子”(子孙最多的p)的答案可以直接用的话,

    就可以省去很多的重复计算,这就是书上启发式合并

     

    DUS ON TREE写法类似板子(恕我无知,没见过其他整法)

    #include<cstdio>
    #include<vector>
    #include<algorithm>
    #include<iostream>
    #include<set>
    using namespace std;
    typedef long long ll;
    const int maxn = 1e5 + 7;
    ll list[maxn];
    ll ans, mx;
    int siz[maxn];//根
    int son[maxn];//重儿子
    ll cns[maxn];
    
    vector<int>G[maxn];
    
    void insert(int be, int en) {
    	G[be].push_back(en);
    }
    int  dfs(int x, int fa) {
    	siz[x] = 1;
    	int c = 0;
    	for(int p : G[x]) {
    		if (p == fa) continue;
    		dfs(p, x);
    		siz[x] += siz[p];
    		if (c < siz[p]) {
    			c = siz[p];
    			son[x] = p;
    		}
    	}
    	return 0;
    }
    ll cnt[maxn];//出现次数
    
    int cal(int x, int fa, int cn, int ban) {
    	cnt[list[x]] += cn;
    
    	if (cnt[list[x]] > mx) {
    		mx = cnt[list[x]];//times
    		ans = list[x];
    	}
    	else if (cnt[list[x]] == mx) {
    		ans += list[x];
    	}
    
    	for (int p : G[x]) {
    		if (p == fa || p == ban) continue;
    		cal(p, x, cn, ban);
    	}
    	return 0;
    }
    int dfs2(int x, int fa,int f) {
    	for (int p : G[x]) {
    		if (p == fa || p == son[x]) continue;
    		
    		dfs2(p, x, 1);
    	}
    	if (son[x] ) {
    		dfs2(son[x], x, 0);
    	}
    	cal(x, fa, 1, son[x]);
    
    	cns[x] = ans;
    
    	if (f == 1) {
    		cal(x, fa, -1, 0);//把树清理干净
    		ans = 0;
    		mx = 0;
    	}
    	return 0;
    }
    
    
    int main() {
    	int n;
    	int be, en;
    	ans = 0;
    	mx = 0;
    	scanf("%d", &n);
    	for (int i = 1; i <= n; i++) {
    		scanf("%lld", &list[i]);
    	}
    	for (int i = 1; i < n; i++) {
    		scanf("%d %d", &be, &en);
    		insert(be, en);
    		insert(en, be);
    	}
    	dfs(1, -1);
    	dfs2(1, -1, 0);
    	for (int i = 1; i <= n; i++) {
    		if (i == 1) printf("%lld", cns[i]);
    		else printf(" %lld", cns[i]);
    	}
    	printf("
    ");
    	return 0;
    }
    

      

     
    寻找真正的热爱
  • 相关阅读:
    我的书单
    写一个小demo过程中遇到的各种问题 学生管理考勤系统(网页模拟)
    高程三 面向对象程序设计
    JavaScript 函数与对象的 简单区别
    高程三 基本包装类型部分的学习
    巨简单巨丑的计算器(写的我快自闭了)
    checked选择器实现tab切换
    JavaScript进行简单的随即验证码生成(适合和我一样刚入门一本完整的教材书都没看完的弟弟)
    dom编程艺术章12
    vue插件开发与发布
  • 原文地址:https://www.cnblogs.com/lesning/p/12249955.html
Copyright © 2011-2022 走看看