zoukankan      html  css  js  c++  java
  • [模板] 长链剖分

    长链剖分

    简介

    对每个节点 (p), 定义 (operatorname{len} (p)) 表示 (p) 到它子树中叶子节点的最大长度.

    类似重链剖分, 把每个节点 (p) 的儿子中 (operatorname{len}) 最大的设为它的重儿子. 边 ((p,son(p))) 称为重边.

    把重边组成的极长子链称为重链(或者长链).

    长链剖分可以保证一个性质:

    [egin{equation} ext{长链总长度} le n end{equation} ]

    虽然很显然, 但这个性质保证了一些利用长链剖分的算法的复杂度.

    应用

    求一个点的k级祖先

    预处理 (O(n log n)), 单次询问 (O(1)).

    其实并没有什么卵用, 可以被倍增替代

    优化一些关于长度的dp

    先咕了...

    例题: bzoj4543: [POI2014]Hotel加强版

    可以得到一个关于链长度的dp方程, 因此利用长链剖分优化即可.

    开空间时:

    • 对于(f) 数组, 重链顶 (p) 和它的重链上的儿子只会用到 (mem[f[p] ... f[p]+len[p]-1]) 的空间;
    • 对于(g) 数组, 重链顶 (p) 和它的重链上的儿子会用到 (mem[g[p]-len[p]+1 ... g[p]+len[p]-1]) 的空间.

    因此开空间时需要开两倍... 详见代码.

    #include<cstdio>
    #include<iostream>
    #include<cmath>
    #include<cstring>
    #include<algorithm>
    #include<set>
    #include<map>
    using namespace std;
    #define rep(i,l,r) for(register int i=(l);i<=(r);++i)
    #define repdo(i,l,r) for(register int i=(l);i>=(r);--i)
    #define il inline
    typedef double db;
    typedef long long ll;
    
    //---------------------------------------
    const int nsz=100050;
    
    int n;
    ll ans=0;
    struct te{int t,pr;}edge[nsz*2];
    int hd[nsz],pe=1;
    void adde(int f,int t){edge[++pe]=(te){t,hd[f]};hd[f]=pe;}
    void adddb(int f,int t){adde(f,t);adde(t,f);}
    #define forg(p,i,v) for(int i=hd[p],v=edge[i].t;i;i=edge[i].pr,v=edge[i].t)
    
    int len[nsz]{-1},son[nsz];
    ll mem[nsz*5],*f[nsz],*g[nsz],*pm=mem;
    void initp(int p,int l){ //开空间
    	f[p]=pm,pm+=(l<<1)+2,g[p]=pm,pm+=l+2;
    }
    
    void dfs1(int p,int f){
    	son[p]=0,len[p]=0;
    	forg(p,i,v){
    		if(v==f)continue;
    		dfs1(v,p);
    		if(len[v]>len[son[p]])son[p]=v,len[p]=len[v]+1;
    	}
    }
    
    void dfs2(int p,int fa){
    	if(son[p]){
    		f[son[p]]=f[p]+1,g[son[p]]=g[p]-1;
    		dfs2(son[p],p);
    	}
    	f[p][0]=1;
    	ans+=g[p][0];
    	forg(p,i,v){
    		if(v==fa||v==son[p])continue;
    		initp(v,len[v]);
    		dfs2(v,p);
    		rep(j,0,len[v]){
    			if(j)ans+=f[p][j-1]*g[v][j];
    			ans+=g[p][j+1]*f[v][j];
    		}
    		rep(j,0,len[v]){
    			g[p][j+1]+=f[p][j+1]*f[v][j];
    			if(j)g[p][j-1]+=g[v][j];
    			f[p][j+1]+=f[v][j];
    		}
    	}
    }
    
    int main(){
    	ios::sync_with_stdio(0),cin.tie(0);
    	cin>>n;
    	int a,b;
    	rep(i,1,n-1)cin>>a>>b,adddb(a,b);
    	dfs1(1,0);
    	initp(1,len[1]);
    	dfs2(1,0);
    	cout<<ans<<'
    ';
    	return 0;
    }
    
  • 相关阅读:
    HTML5 的成长之路
    黑马程序员——JAVA基础之数组
    黑马程序员——JAVA基础之函数,重载,内存结构
    黑马程序员——JAVA基础之程序控制流结构之循环结构,循环嵌套
    黑马程序员——JAVA基础之程序控制流结构之判断结构,选择结构
    黑马程序员——JAVA基础之语法、命名规则
    黑马程序员——JAVA基础之常用DOS命令和环境变量的配置
    Android应用开发高效工具集1---ant构建简单Android项目
    10个你能参与并学习的Java开源项目
    Anroid 异常:is not valid; is your activity running?
  • 原文地址:https://www.cnblogs.com/ubospica/p/10485904.html
Copyright © 2011-2022 走看看