cf1286B——构造,启发式合并

Posted zsben991126

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了cf1286B——构造,启发式合并相关的知识,希望对你有一定的参考价值。

/*
思路:借鉴 dsu on tree,自底往上进行合并
给每个叶子结点赋初始值为1,每个结点依次合并每个儿子
为了防止冲突,子树在被并入当前结点时,所有结点都要重新编号
最后把当前结点插到子树里去,由于又插进了一个结点,所以再重新编号一次
每个最多被重新编号n次,复杂度O(n^2) 
*/
#include<bits/stdc++.h>
#include<vector>
using namespace std;
#define N 2005

int n,p[N],c[N],id[N];
vector<int>G[N];
vector<int> subtree[N];
int root;

void dfs(int u,int pre){
    if(G[u].size()==1 && pre==0){
        subtree[u].push_back(u);
        id[u]=1;return;
    }
    
    for(auto v:G[u])
        if(v!=pre)dfs(v,u);
        
    int tot=0;
    for(auto v:G[u])if(v!=pre){
        for(auto x:subtree[v]){
            subtree[u].push_back(x);
            id[x]+=tot;
        }
        tot+=subtree[v].size();
        subtree[v].clear();
    }
    
    stack<int>stk;
    while(stk.size())stk.pop();
    
    while(subtree[u].size()>=c[u]){
        stk.push(subtree[u].back());
        subtree[u].pop_back();
    }
    subtree[u].push_back(u);
    id[u]=c[u];
    while(stk.size()){
        int now=stk.top();stk.pop();
        id[now]++;
        subtree[u].push_back(now);
    }
}

int size[N];
void getsize(int u,int pre){
    size[u]=1;
    for(auto v:G[u]){
        if(v==pre)continue;
        getsize(v,u);size[u]+=size[v];
    }
}

int main(){
    cin>>n;
    for(int i=1;i<=n;i++){
        cin>>p[i]>>c[i];
        c[i]++;
        G[i].push_back(p[i]);
        G[p[i]].push_back(i);
        if(p[i]==0)root=i;
    }
    
    getsize(root,0);
    for(int i=1;i<=n;i++)
        if(size[i]<c[i]){
            puts("NO");return 0;
        }
    
    dfs(root,0);
    puts("YES");
    for(int i=1;i<=n;i++)cout<<id[i]<<" ";
}

以上是关于cf1286B——构造,启发式合并的主要内容,如果未能解决你的问题,请参考以下文章

#线段树合并树上启发式合并#CF600E Lomsat gelral

CF600ELomsat gelral——树上启发式合并

CF 600 E Lomsat gelral —— 树上启发式合并

CF600E Lomsat gelral(树上启发式合并)

CF600ELomset gelral 题解(树上启发式合并)

CF 600E 树上启发式合并