• bzoj 4543: [POI2014]Hotel加强版


    Description

    给出一棵树求三元组 ((x,y,z)\,,x<y<z) 满足三个点两两之间距离相等,求三元组的数量

    Solution

    考虑暴力 (DP)
    (f[i][j]) 表示距离点 (i) 的子树内距离为 (j) 的点的数量
    (g[i][j]) 表示 (i) 子树内的一个二元组 ((x,y)) 满足 (dis(x,lca)=dis(y,lca)=dis(i,lca)+j) 的二元组的数量,可以视为等待与子树外合并的二元组的数量
    显然有转移:
    (ans+=g[x][0])
    (ans+=f[son][j]*g[x][j+1]+f[x][j-1]*g[son][j])

    (f[x][j]=f[son][j-1])
    (g[x][j]=g[son][j+1])
    (g[x][j]=f[x][j]*f[son][j-1])

    这样转移是 (O(n^2))
    对于深度为下标的树形 (DP),考虑长链剖分优化:
    (DP) 转移之前, (f[x],g[x]) 是没有值的,初值要设为某个儿子的 (DP)
    并且这个时候的转移仅仅是 (f[x][j]=f[son][j-1]),(g[x][j]=g[son][j+1])
    相当于一个数组位移,直接用指针优化,可以做到 (O(1)),所以用所在链最长的儿子来赋初值复杂度最优,其余儿子暴力转移
    这样做复杂度均摊就是 (O(n)) 的了,一条链只会在链顶被枚举到,且链不相交,所以每个点只会被枚一次
    空间对于每一个链动态开空间,空间复杂度也是 (O(n))

    #include<bits/stdc++.h>
    using namespace std;
    template<class T>void gi(T &x){
    	int f;char c;
    	for(f=1,c=getchar();c<'0'||c>'9';c=getchar())if(c=='-')f=-1;
    	for(x=0;c<='9'&&c>='0';c=getchar())x=x*10+(c&15);x*=f;
    }
    typedef long long ll;
    const int N=1e5+10;
    int n,head[N],nxt[N*2],to[N*2],num=0,dep[N],mx[N];
    inline void link(int x,int y){nxt[++num]=head[x];to[num]=y;head[x]=num;}
    ll lis[N*5],*f[N],*g[N],*st=lis+5,ans=0;
    inline void dfs(int x,int fa){
    	mx[x]=x;
    	for(int i=head[x],u;i;i=nxt[i]){
    		if((u=to[i])==fa)continue;
    		dep[u]=dep[x]+1;dfs(u,x);
    		if(dep[mx[u]]>dep[mx[x]])mx[x]=mx[u];
    	}
    	for(int i=head[x],u;i;i=nxt[i]){
    		if((u=to[i])==fa || (mx[u]==mx[x] && x!=1))continue;
    		st+=dep[mx[u]]-dep[x]+1;
    		f[mx[u]]=st;
    		g[mx[u]]=++st;
    		st+=(dep[mx[u]]-dep[x])*2+1;
    	}
    }
    inline void dfs2(int x,int fa){
    	for(int i=head[x],u;i;i=nxt[i]){
    		if((u=to[i])==fa)continue;
    		dfs2(u,x);
    		if(mx[u]==mx[x])f[x]=f[u]-1,g[x]=g[u]+1;
    	}
    	f[x][0]=1;ans+=g[x][0];
    	for(int i=head[x],u;i;i=nxt[i]){
    		if((u=to[i])==fa || mx[u]==mx[x])continue;
    		for(int j=dep[mx[u]]-dep[x];j>=0;j--)
    			ans+=g[x][j+1]*f[u][j]+g[u][j]*(j?f[x][j-1]:0);
    		for(int j=dep[mx[u]]-dep[x];j>=0;j--){
    			f[x][j+1]+=f[u][j];
    			g[x][j]+=g[u][j+1];
    			g[x][j]+=f[x][j]*(j?f[u][j-1]:0);
    		}
    	}
    }
    int main(){
      freopen("pp.in","r",stdin);
      freopen("pp.out","w",stdout);
      cin>>n;
      int x,y;
      for(int i=1;i<n;i++)gi(x),gi(y),link(x,y),link(y,x);
      dfs(1,1);dfs2(1,1);
      cout<<ans<<endl;
      return 0;
    }
    
    
  • 相关阅读:
    dhl:有用的sql语句(我用到的)更新中....
    dhl:给Button设背景图片
    遍历一个类中的每一个属性、方法、公共字段
    swf、wmv、mov、RM几种常见格式视频播放器代码!
    理解Windows中的路由表和默认网关
    主/辅DNS服务器详细配置
    用组策略彻底禁止USB存储设备、光驱、软驱、ZIP软驱
    DHCP中继原理及配置--路由器
    路由器NAT功能配置简介
    网络负载平衡群集
  • 原文地址:https://www.cnblogs.com/Yuzao/p/8982991.html
Copyright © 2020-2023  润新知