zoukankan      html  css  js  c++  java
  • bzoj 5341: [Ctsc2018]暴力写挂

    Description

    Solution

    边分治+边分树合并
    这个题很多做法都是启发式合并的复杂度的,都有点卡
    以前有个套路叫做线段树合并优化启发式合并,消掉一个 (log)
    这个题思路类似,建出边分树,通过一些操作把它变成线段树,就可以线段树合并了
    首先边分树的相关定理:
    如果一棵包含 (N) 个结点的树中每个点的度均不大于 (D),那么存在一条边,使得分出的两棵子树的结点个数在 ([N/(D+1),N*D/(D+1)])
    那么边分树的深度和度数是相关的,我们只需要通过加虚点把这棵树变成二叉树就好了

    回到这个题:
    枚举第二棵树的 (lca) , 然后剩下的就是在第二棵树中选出在第一棵树中 (dep[x]+dep[y]-dep[lca(x,y)]) 的最大值
    我们发现这个要求的东西就是 (x,y) 到根的路径的交,所以可以不考虑第一棵树的 (lca)
    其中 (x,y) 都来自这个 (lca) 的不同子树内
    每次插入一个点就像线段树那样更新就行了,不同的是你不能准确定位到这个叶子节点,你需要在 (build) 的时候顺便存一下对应关系
    枚举第二棵树的 (lca) 再合并子树的边分树,顺便更新一下答案就行了

    #include<bits/stdc++.h>
    #define vc vector<edge>::iterator 
    #define pb push_back
    using namespace std;
    typedef long long ll;
    const int N=750000,M=8510000,T=N*2;
    int n,V,sz[N],sum,son[N]={N},val[T],ls[T],rs[T],dep[N],fa[T],tt=0;
    ll f[N][20],dis[N],fl[M],fr[M],ans=0,D;int lm[M],rm[M],rt[N/2],id[M];
    struct edge{
    	int x,v;
    	edge(){}
    	edge(int _x,int _v){x=_x;v=_v;}
    }q[N];
    vector<edge>G1[N],G2[N/2];
    inline void add(int x,int y,int z,vector<edge>*G){
    	G[x].pb(edge(y,z));G[y].pb(edge(x,z));
    }
    inline void build(int x,int last){
    	for(vc it=G1[x].begin();it!=G1[x].end();++it){
    		if(it->x==last)continue;
    		dis[it->x]=dis[x]+it->v;build(it->x,x);
    	}
    	int l=1,r=0;edge u,v;
    	for(vc it=G1[x].begin();it!=G1[x].end();++it)if(it->x!=last)q[++r]=*it;
    	while(l+2<=r){
    		int o=++V;u=q[l++],v=q[l++];
    		add(o,u.x,u.v,G1);add(o,v.x,v.v,G1);
    		q[++r]=edge(o,0);
    	}
    	vector<edge>().swap(G1[x]);
    	while(l<=r)add(x,q[l].x,q[l].v,G1),l++;
    }
    inline void getdis(int x,int last,int d){
    	for(vc it=G1[x].begin();it!=G1[x].end();++it){
    		if(it->x==last || it->x==-1)continue;
    		f[it->x][d]=f[x][d]+it->v;getdis(it->x,x,d);
    	}
    }
    inline void getedge(int x,int last,int &ex,int &ey){
    	sz[x]=1;
    	for(int i=G1[x].size()-1,u;i>=0;i--){
    		if((u=G1[x][i].x)==last || u==-1)continue;
    		getedge(u,x,ex,ey);sz[x]+=sz[u];
    		if(son[u]<son[ey])ex=x,ey=u;
    	}
    	son[x]=abs(sum-2*sz[x]);
    }
    inline int solve(int x,int S,int d){
    	if(S==1){dep[x]=d;return x;}
    	int ex=0,ey=0,o=++V;
    	getdis(x,x,d);
    	sum=S;getedge(x,x,ex,ey);
    	for(vc it=G1[ex].begin();it!=G1[ex].end();++it)
    		if(it->x==ey){val[o]=it->v;it->x=-1;break;}
    	for(vc it=G1[ey].begin();it!=G1[ey].end();++it)
    		if(it->x==ex){it->x=-1;break;}
    	fa[ls[o]=solve(ex,S-sz[ey],d+1)]=o;
    	fa[rs[o]=solve(ey,sz[ey],d+1)]=o;
    	return o;
    }
    inline int ins(int x){
    	for(int i=dep[x],u=x,la=x;i>=1;i--){
    		id[++tt]=fa[x];fl[tt]=fr[tt]=-1ll<<60;
    		if(ls[fa[x]]==x)fl[tt]=max(fl[tt],dis[u]+f[u][i]),lm[tt]=la;
    		if(rs[fa[x]]==x)fr[tt]=max(fr[tt],dis[u]+f[u][i]),rm[tt]=la;
    		la=tt;x=fa[x];
    	}
    	return tt;
    }
    inline int merge(int x,int y){
    	if(!x||!y)return x+y;
    	ans=max(ans,(fl[x]+fr[y]+val[id[x]])/2-D);
    	ans=max(ans,(fl[y]+fr[x]+val[id[x]])/2-D);
    	fl[x]=max(fl[x],fl[y]);fr[x]=max(fr[x],fr[y]);
    	lm[x]=merge(lm[x],lm[y]);rm[x]=merge(rm[x],rm[y]);
    	return x;
    }
    inline void dfs(int x,int last,ll d){
    	rt[x]=ins(x);ans=max(ans,dis[x]-d);
    	for(vc it=G2[x].begin();it!=G2[x].end();++it){
    		if(it->x==last)continue;
    		dfs(it->x,x,d+it->v);D=d;
    		rt[x]=merge(rt[x],rt[it->x]);
    	}
    }
    int main(){
      freopen("pp.in","r",stdin);
      freopen("pp.out","w",stdout);
      cin>>n;V=n;
      int x,y,z;
      for(int i=1;i<n;i++)scanf("%d%d%d",&x,&y,&z),add(x,y,z,G1);
      for(int i=1;i<n;i++)scanf("%d%d%d",&x,&y,&z),add(x,y,z,G2);
      build(1,1);solve(1,V,0);dfs(1,1,0);
      cout<<ans<<endl;
      return 0;
    }
    
    
  • 相关阅读:
    DELPHI 画报表 画表头 stringgrid控件
    蜂巢 Thinking in Agile 我们需要怎样的软件过程(1)
    小博一周年了 将开源进行到底
    Windows Mobile下实现图片的3D效果
    蜂巢 Thinking in Agile 我们需要怎样的软件过程(2)
    Windows 中各种 dll 的导出功能
    以下代码中的两个sizeof用法有问题吗?
    sizeof和strlen
    以下反向遍历array数组的方法有什么错误?
    找错题
  • 原文地址:https://www.cnblogs.com/Yuzao/p/9179670.html
Copyright © 2011-2022 走看看