D34【模板】长链剖分 CF1009F Dominant Indices

视频链接:333 长链剖分【模板】CF1009F Dominant Indices_哔哩哔哩_bilibili

 

 

 

 

 

CF1009F Dominant Indices

Luogu CF1009F Dominant Indices

// 长链剖分+树形DP
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <vector>
using namespace std;

const int N=1e6+5;
vector<int> e[N];
int n,son[N],len[N];
int buf[N],*f[N],*p=buf,ans[N];
//f[x][i]:在x子树内与x的距离为i的节点数

void dfs(int x,int fa){ //长链剖分
  for(int y : e[x]){
    if(y==fa) continue;
    dfs(y,x);
    if(len[son[x]]<len[y]) son[x]=y;
  }
  len[x]=len[son[x]]+1;
}
void DP(int x,int fa){ //树形DP
  f[x][0]=1;
  if(son[x]){
    f[son[x]]=f[x]+1; //共享内存,f[son[x]][i]会被自动保存到f[x][i+1]
    DP(son[x],x);
    ans[x]=ans[son[x]]+1; //继承答案
  } 
  for(int y : e[x]){
    if(y==fa||y==son[x]) continue;
    f[y]=p; p+=len[y]; //给y开头的链分配内存
    DP(y,x);
    for(int j=1; j<=len[y]; j++){
      f[x][j]+=f[y][j-1]; //暴力合并
      if(f[x][j]>f[x][ans[x]] ||
         f[x][j]==f[x][ans[x]] && j<ans[x])
           ans[x]=j; //更新答案
    }
  }
  if(f[x][ans[x]]==1) ans[x]=0; //修正
}
int main(){
  scanf("%d",&n);
  for(int i=1; i<n; i++){
    int x,y; scanf("%d%d",&x,&y);
    e[x].push_back(y); e[y].push_back(x);
  }    
  dfs(1,0);
  f[1]=p; p+=len[1]; //给树根长链分配内存
  DP(1,0);
  for(int i=1;i<=n;++i) printf("%d\n",ans[i]);
}

 

练习:

Luogu P5904 [POI2014] HOT-Hotels 加强版

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

#define LL long long
const int N=100005;
vector<int> e[N];
int n,len[N],son[N];
LL buf[N<<2],*f[N],*g[N],*p=buf,ans;

void dfs(int x,int fa){ //长链剖分
  for(int y : e[x]){
    if(y==fa) continue;
    dfs(y,x);
    if(len[son[x]]<len[y]) son[x]=y;
  }
  len[x]=len[son[x]]+1;
}
void DP(int x,int fa){ //树形DP
  f[x][0]=1;
  if(son[x]){
    f[son[x]]=f[x]+1;
    g[son[x]]=g[x]-1;
    DP(son[x],x);
  }
  ans+=g[x][0];
  for(int y : e[x]){
    if(y==fa||y==son[x]) continue;
    f[y]=p; p+=len[y]<<1;
    g[y]=p; p+=len[y]<<1;
    DP(y,x);
    for(int j=0;j<len[y];++j){
      if(j) ans+=f[x][j-1]*g[y][j];
      ans+=g[x][j+1]*f[y][j];
    }
    for(int j=0;j<len[y];++j){
      g[x][j+1]+=f[x][j+1]*f[y][j];
      if(j) g[x][j-1]+=g[y][j];
      f[x][j+1]+=f[y][j];
    }
  }
}
int main(){
  scanf("%d",&n);
  for(int i=1; i<n; i++){
    int x,y; scanf("%d%d",&x,&y);
    e[x].push_back(y); e[y].push_back(x);
  } 
  dfs(1,0);
  f[1]=p;p+=len[1]<<1; g[1]=p;p+=len[1]<<1;
  DP(1,0);
  printf("%lld\n",ans);
}
View Code

Luogu P4292 [WC2010] 重建计划

Luogu P3899 [湖南集训] 更为厉害

攻略 - BZOJ by HydroOJ

Luogu P5903 【模板】树上 k 级祖先

 

posted @ 2023-08-10 08:57  董晓  阅读(354)  评论(0编辑  收藏  举报