zoukankan      html  css  js  c++  java
  • 边分治学习笔记

    边分治学习笔记

    用途

    边分治和点分治类似,每次选取一条边,将树尽可能均匀地分成两部分,然后再去递归左右两个子树统计信息。

    如果直接在原树上进行边分治,遇到菊花图的时候复杂度就假了。

    所以要把原树转成一棵二叉树再进行分治。

    具体的做法是:如果一个点的儿子个数小于等于两个就直接建树,否则新建两个节点,把原树中的儿子按照奇偶性分给两个儿子。

    新建出来的点根据题目要求给予恰当的信息即可。

    边分治的优点在于每次只需要处理两个子树合并后的信息,更好维护一些。

    例题:【BZOJ2870】最长道路tree

    题目传送门

    分析

    路径统计的问题不难想到用分治去解决。

    这题用边分治可能更好写一些,如果用点分治的话还要套数据结构。

    考虑把经过某条边的路径合并。

    我们把两边子树的从根出发的路径都提出来,这样的话问题转化成:

    每条链有长度和权值两个属性,把两个链合并得到的是权值的最小值乘上长度和。

    对两个子树内的路径按照权值排序后分别用双指针扫一遍即可。

    代码

    #include<cstdio>
    #include<cmath>
    #include<cstring>
    #include<algorithm>
    #include<iostream>
    #include<vector>
    #define rg register
    inline int read(){
    	rg int x=0,fh=1;
    	rg char ch=getchar();
    	while(ch<'0' || ch>'9'){
    		if(ch=='-') fh=-1;
    		ch=getchar();
    	}
    	while(ch>='0' && ch<='9'){
    		x=(x<<1)+(x<<3)+(ch^48);
    		ch=getchar();
    	}
    	return x*fh;
    }
    const int maxn=2e5+5;
    int h[maxn],tot=2,n,cnt,a[maxn];
    struct asd{
    	int to,nxt,val;
    }b[maxn];
    void ad(rg int aa,rg int bb,rg int cc){
    	b[tot].to=bb;
    	b[tot].nxt=h[aa];
    	b[tot].val=cc;
    	h[aa]=tot++;
    }
    std::vector<int> son[maxn];
    void dfs(rg int now,rg int lat){
    	for(rg int i=h[now];i!=-1;i=b[i].nxt){
    		rg int u=b[i].to;
    		if(u==lat) continue;
    		son[now].push_back(u);
    		dfs(u,now);
    	}
    }
    void rebuild(){
    	tot=2;
    	memset(h,-1,sizeof(h));
    	for(rg int now=1;now<=n;now++){
    		if(son[now].size()<=2){
    			for(rg int i=0,len=son[now].size();i<len;i++){
    				rg int u=son[now][i];
    				ad(now,u,1),ad(u,now,1);
    			}
    		} else {
    			rg int ac1=++n,ac2=++n;
    			a[ac1]=a[ac2]=a[now];
    			ad(now,ac1,0),ad(ac1,now,0);
    			ad(now,ac2,0),ad(ac2,now,0);
    			for(rg int i=0,len=son[now].size();i<len;i++){
    				if(i&1) son[ac2].push_back(son[now][i]);
    				else son[ac1].push_back(son[now][i]);
    			}
    		}
    	}
    }
    int maxsiz,rt,totsiz,siz[maxn];
    bool vis[maxn];
    void getroot(rg int now,rg int lat){
    	siz[now]=1;
    	for(rg int i=h[now];i!=-1;i=b[i].nxt){
    		rg int u=b[i].to;
    		if(vis[i>>1] || u==lat) continue;
    		getroot(u,now);
    		siz[now]+=siz[u];
    		rg int cs=std::max(siz[u],totsiz-siz[u]);
    		if(cs<maxsiz){
    			maxsiz=cs,rt=i;
    		}
    	}
    }
    struct jie{
    	int val,dep;
    	jie(){}
    	jie(rg int aa,rg int bb){
    		val=aa,dep=bb;
    	}
    }sta[2][maxn];
    int tp[2];
    void getdis(rg int op,rg int now,rg int lat,rg int dep,rg int val){
    	val=std::min(val,a[now]);
    	sta[op][++tp[op]]=jie(val,dep);
    	for(rg int i=h[now];i!=-1;i=b[i].nxt){
    		rg int u=b[i].to;
    		if(vis[i>>1] || u==lat) continue;
    		getdis(op,u,now,dep+b[i].val,val);
    	}
    }
    bool cmp(jie aa,jie bb){
    	return aa.val>bb.val;
    }
    long long ans=0;
    void solve(rg int now,rg int sz){
    	totsiz=sz,maxsiz=0x3f3f3f3f;
    	getroot(now,0);
    	if(maxsiz==0x3f3f3f3f) return;
    	vis[rt>>1]=1;
    	tp[0]=tp[1]=0;
    	getdis(0,b[rt].to,0,0,0x3f3f3f3f);
    	getdis(1,b[rt^1].to,0,0,0x3f3f3f3f);
    	std::sort(sta[0]+1,sta[0]+tp[0]+1,cmp);
    	std::sort(sta[1]+1,sta[1]+tp[1]+1,cmp);
    	for(rg int i=1,j=1,maxdep=0;i<=tp[0];i++){
    		while(j<=tp[1] && sta[1][j].val>=sta[0][i].val){
    			maxdep=std::max(maxdep,sta[1][j].dep);
    			j++;
    		}
    		if(j!=1){
    			ans=std::max(ans,1LL*sta[0][i].val*(maxdep+sta[0][i].dep+1+b[rt].val));
    		}
    	}
    	for(rg int i=1,j=1,maxdep=0;i<=tp[1];i++){
    		while(j<=tp[0] && sta[0][j].val>=sta[1][i].val){
    			maxdep=std::max(maxdep,sta[0][j].dep);
    			j++;
    		}
    		if(j!=1){
    			ans=std::max(ans,1LL*sta[1][i].val*(maxdep+sta[1][i].dep+1+b[rt].val));
    		}
    	}
    	rg int nsz=siz[b[rt].to],nrt=rt;
    	solve(b[nrt].to,nsz);
    	solve(b[nrt^1].to,sz-nsz);
    }
    int main(){
    	memset(h,-1,sizeof(h));
    	n=cnt=read();
    	for(rg int i=1;i<=n;i++) a[i]=read();
    	rg int aa,bb;
    	for(rg int i=1;i<n;i++){
    		aa=read(),bb=read();
    		ad(aa,bb,1);
    		ad(bb,aa,1);
    	}
    	dfs(1,0);
    	rebuild();
    	solve(1,n);
    	printf("%lld
    ",ans);
    	return 0;
    }
    
  • 相关阅读:
    深度学习--文本摘要生成简介
    hive进阶 技巧
    python 库 imgaug数据增强
    评分卡模型
    spark-submit 参数总结
    H2O中的随机森林算法介绍及其项目实战(python实现)
    kafka 基本原理简介
    Xshell 服务器配置
    yapi内网部署 centos
    pm2使用 node 进程管理
  • 原文地址:https://www.cnblogs.com/liuchanglc/p/14603001.html
Copyright © 2011-2022 走看看