D32 树上启发式合并 CF600E Lomsat gelral

视频链接:330 树上启发式合并 CF600E Lomsat gelral_哔哩哔哩_bilibili

 

 

 

Luogu CF600E Lomsat gelral

#include <iostream>
#include <cstring>
#include <algorithm>
#include <vector>
#define LL long long 
using namespace std;
int read(){
  char c=getchar(); int x=0,f=1;
  while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
  while(c>='0'&&c<='9') x=x*10+c-'0',c=getchar();
  return x*f;
}

const int N=1e5+10;
// col[x]:节点的颜色编号, son[x]:重儿子, 
// cnt[i]:颜色编号i的数量
int n,col[N],siz[N],son[N],cnt[N],mx;
LL sum,ans[N];
vector<int> e[N];

void dfs1(int x,int fa){ //重链剖分
  siz[x]=1;
  for(int y : e[x]){
    if(y==fa) continue;
    dfs1(y,x);
    siz[x]+=siz[y];
    if(siz[y]>siz[son[x]]) son[x]=y;
  }
}
void add(int x,int fa,int son){
  cnt[col[x]]++;
  if(cnt[col[x]]>mx) mx=cnt[col[x]],sum=col[x];
  else if(cnt[col[x]]==mx) sum+=col[x];
  
  for(int y : e[x]) //重子树除外
    if(y!=fa && y!=son) add(y,x,son);
}
void sub(int x,int fa){
  cnt[col[x]]--;
  for(int y : e[x])
    if(y!=fa) sub(y,x);
}
void dfs2(int x, int fa, int opt){
  for(int y : e[x]) //先搜轻儿子
    if(y!=fa && y!=son[x]) dfs2(y,x,0);
  if(son[x]) dfs2(son[x],x,1); //后搜重儿子
  
  add(x,fa,son[x]); //累加x和轻子树贡献
  ans[x]=sum;       //存储答案
  if(!opt)sub(x,fa),sum=mx=0; //减掉轻子树贡献
}
int main(){
  n=read();
  for(int i=1; i<=n; i++) col[i]=read();
  for(int i=1; i<=n-1; i++){
    int x=read(),y=read();
    e[x].push_back(y); e[y].push_back(x);
  }
  dfs1(1,0);
  dfs2(1,0,0);
  for(int i=1; i<=n; i++) printf("%lld ",ans[i]);
  return 0;
}

 

Luogu U41492 树上数颜色

#include <iostream>
#include <cstring>
#include <algorithm>
#include <vector>
using namespace std;

#define LL long long 
const int N=2e5+10;
// col[x]:节点的颜色编号, son[x]:重儿子, 
// cnt[i]:颜色编号i的数量
int n,col[N],siz[N],son[N],cnt[N];
LL sum,ans[N];
vector<int> e[N];

void dfs1(int x,int fa){ //重链剖分
  siz[x]=1;
  for(int y : e[x]){
    if(y==fa) continue;
    dfs1(y,x);
    siz[x]+=siz[y];
    if(siz[y]>siz[son[x]]) son[x]=y;
  }
}
void add(int x,int fa,int son){
  if(!cnt[col[x]]) ++sum;
  cnt[col[x]]++;
  for(int y : e[x]) //重儿子除外
    if(y!=fa && y!=son) add(y,x,son);
}
void sub(int x,int fa){
  cnt[col[x]]--;
  for(int y : e[x])
    if(y!=fa) sub(y,x);
}
void dfs2(int x, int fa, int opt){
  for(int y : e[x]) //先搜轻儿子
    if(y!=fa && y!=son[x]) dfs2(y,x,0);
  if(son[x]) dfs2(son[x],x,1); //后搜重儿子
  
  add(x,fa,son[x]); //累加x和轻子树贡献
  ans[x]=sum;       //存储答案
  if(!opt) sub(x,fa),sum=0; //减掉轻子树贡献
}
int main(){
  scanf("%d",&n);
  for(int i=1; i<n; i++){
    int u,v; scanf("%d%d",&u,&v);
    e[u].push_back(v);
    e[v].push_back(u);
  }
  for(int i=1; i<=n; i++) scanf("%d",&col[i]);  
  dfs1(1,0);
  dfs2(1,0,0);
  for(int i=1; i<=n; i++) printf("%d\n",ans[i]);
  return 0;
}
View Code

 

posted @ 2023-08-08 09:08  董晓  阅读(460)  评论(1编辑  收藏  举报