码迷,mamicode.com
首页 > 其他好文 > 详细

启发式合并

时间:2018-09-22 12:59:51      阅读:213      评论:0      收藏:0      [点我收藏+]

标签:target   names   while   using   dfs   sum   net   cin   tor   

推荐博客 : https://blog.csdn.net/zjznku/article/details/65937416

其实启发式合并核心思想就是将小的集合合并到大的集合上面

 

例题 : HDU 4358

求一颗树上以每个点为子树中权值出现 k 次的个数有多少个

 

#include <bits/stdc++.h>
using namespace std;
#define ll long long
const int maxn = 1e5+5;

int n, k;
int a[maxn];
vector<int>ve[maxn], vv;
int size[maxn], son[maxn];
int que[maxn];

void init(){
    vv.clear();
    for(int i = 1; i <= 100000; i++) ve[i].clear();
    memset(size, 0, sizeof(size));
    memset(son, 0, sizeof(son));
}


void dfs1(int x){ //求出每个结点的重儿子
    size[x] = 1;
    
    int num = 0;
    for(int i = 0; i < ve[x].size(); i++){
        int to = ve[x][i];
        dfs1(to);
        size[x] += size[to];
        if (size[to] > num) {num = size[to]; son[x] = to;}
    }
}
int sum[maxn], ans[maxn];
int res = 0;
bool vis[maxn];
 
void edit(int x, int sp){  //更新每个点的贡献
    if (sum[a[x]] == k) res--;
    sum[a[x]] += sp;
    if (sum[a[x]] == k) res++;
    
    for(int i = 0; i < ve[x].size(); i++){
        int to = ve[x][i];
        if (vis[to]) continue;
        edit(to, sp);
    }
}
void dfs(int x, int sp){    //sp表示贡献是否被清空
    for(int i = 0; i < ve[x].size(); i++){ //遍历所有非重儿子的结点
        int to = ve[x][i];
        if (to == son[x]) continue;
        dfs(to, 0);
    }
    if (son[x]) dfs(son[x], 1), vis[son[x]] = 1;
    edit(x, 1); //遍历x的所有结点 添加重儿子以外的贡献
    ans[x] = res;  //记录答案
    
    if (son[x]) vis[son[x]] = 0; //重儿子的标记取消
    if (!sp) edit(x, -1); //贡献取消
}

int main() {
    //freopen("in.txt", "r", stdin);
    //freopen("out.txt", "w", stdout);
    
    int T;
    cin >> T;
    int x, y;
    int kas = 1;
    int sign = 0;
    
    while(T--) {
        if (sign) printf("\n");
        init();
        scanf("%d%d", &n, &k);
        for(int i = 1; i <= n; i++) {
            scanf("%d", &a[i]);
            vv.push_back(a[i]);
        }        
        sort(vv.begin(), vv.end());
        vv.erase(unique(vv.begin(), vv.end()), vv.end());
        for(int i = 1; i <= n; i++) a[i] = lower_bound(vv.begin(), vv.end(), a[i])-vv.begin()+1;
        
         
        for(int i = 1; i < n; i++){
            scanf("%d%d", &x, &y);
            ve[x].push_back(y);     
        }
        dfs1(1); dfs(1, 0);
        int q;
        
        cin >> q;
        for(int i = 1; i <= q; i++) {scanf("%d", &que[i]);}
        printf("Case #%d:\n", kas++);
        for(int i = 1; i <= n; i++) printf("%d\n", ans[que[i]]);
        sign = 1; 
        //for(int i = 1; i <= n; i++) printf("%d ", sum[i]);
    }
    return 0;
}

 

启发式合并

标签:target   names   while   using   dfs   sum   net   cin   tor   

原文地址:https://www.cnblogs.com/ccut-ry/p/9689234.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!