• bzoj1977: [BeiJing2010组队]次小生成树 Tree


    传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=1911

    思路:这题是严格次小生成树

    首先考虑不严格的次小生成树

    我们先求出最小生成树

    然后对每条不在最小生成树的边(x,y),求出x->y路径上的最大的边,把它替换这条边之后的树就可能是次小生成树

    用倍增思想记录max[x][i]表示x的第2^i的祖先到x的边上的最大值就可以做到O(nlogn)

    严格次小稍微有些区别,如果路径最大边和边(x,y)权值相同,就不能替换,而要换严格次大的边

    所以多记一个secmax[x][i]表示x的第2^i的祖先到x的边上的严格最大值即可

    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    const int maxn=100010,maxm=300010,maxk=22;
    using namespace std;
    typedef long long ll;
    int n,m,pre[maxm],now[maxn],son[maxm],val[maxm],delta=(int)1e9+7,tot;ll ans;
    int fa[maxn][maxk],fim[maxn][maxk],sem[maxn][maxk],dep[maxn],f[maxn];bool in[maxm];
    struct Edge{int x,y,v;}E[maxm];
    bool operator <(Edge a,Edge b){return a.v<b.v;} 
    void add(int a,int b,int c){pre[++tot]=now[a],now[a]=tot,son[tot]=b,val[tot]=c;}
    int getfa(int x){return f[x]==x?x:f[x]=getfa(f[x]);}
    void dfs(int x){
    	for (int i=1;i<=18;i++){
    		fa[x][i]=fa[fa[x][i-1]][i-1];
    		int t1=fim[x][i-1],t2=fim[fa[x][i-1]][i-1];
    		fim[x][i]=max(t1,t2);
    		sem[x][i]=max(sem[x][i-1],sem[fa[x][i-1]][i-1]);
    		if (t1!=t2) sem[x][i]=max(sem[x][i],min(t1,t2));
    	}
    	for (int y=now[x];y;y=pre[y]) if (son[y]!=fa[x][0]){
    		dep[son[y]]=dep[x]+1,fa[son[y]][0]=x;
    		fim[son[y]][0]=val[y],dfs(son[y]);
    	}
    }
    
    void kruskal(){
    	sort(E+1,E+1+m);int cnt=0;
    	for (int i=1;i<=n;i++) f[i]=i;
    	for (int i=1;i<=m&&cnt<n-1;i++){
    		int x=E[i].x,y=E[i].y,v=E[i].v;
    		if (getfa(x)==getfa(y)) continue;
    		cnt++,f[getfa(x)]=getfa(y),ans+=v,in[i]=1;
    		add(x,y,v),add(y,x,v);
    	}
    }
    
    int lca(int x,int y){
    	if (dep[x]<dep[y]) swap(x,y);
    	for (int h=dep[x]-dep[y],i=18;i>=0&&h;i--) if (h&(1<<i)) x=fa[x][i];
    	if (x==y) return x;
    	for (int i=18;i>=0;i--)
    		if (fa[x][i]!=fa[y][i])
    			x=fa[x][i],y=fa[y][i];
    	return fa[x][0];
    }
    
    void query(int x,int u,int v){
    	int max1=0,max2=0;
    	for (int i=18,h=dep[x]-dep[u];i>=0;i--) if (h&(1<<i)){
    		if (fim[x][i]>max1) max2=max1,max1=fim[x][i];
    		max2=max(max2,sem[x][i]),h-=(1<<i);
    	}
    	if (v==max1) delta=min(delta,v-max2);
    	else delta=min(delta,v-max1);
    }
    
    void solve(int id){
    	int x=E[id].x,y=E[id].y,v=E[id].v,u=lca(x,y);
    	query(x,u,v),query(y,u,v);
    }
    
    int main(){
    	scanf("%d%d",&n,&m);
    	for (int i=1,x,y,z;i<=m;i++) scanf("%d%d%d",&x,&y,&z),E[i]=(Edge){x,y,z};
    	kruskal(),dfs(1);
    	for (int i=1;i<=m;i++) if (!in[i]) solve(i);
    	printf("%lld
    ",ans+delta);
    	return 0;
    }


  • 相关阅读:
    如何为Android写一个PhoneGap插件
    Javascript高性能动画与页面渲染
    jquery mobile Popup
    android学习资料免费下载
    锋利的jquery第2版高清 pdf
    android获取sd卡最后一张照片
    mongodb 基础
    django 实现读写分离
    docker 部署django方式
    mysql 主从读写
  • 原文地址:https://www.cnblogs.com/thythy/p/5493475.html
Copyright © 2020-2023  润新知