zoukankan      html  css  js  c++  java
  • 【【模板】严格次小生成树[BJWC2010]】

    树上的路径怎么能没有树剖

    显然,次小生成树和最小生成树只在一条边上有差距,于是我们就可以枚举这一条边,将所有边加入最小生成树,之后再来从这些并不是那么小的生成树中找到那个最小的

    我们往最小生成树里加入一条边一定会在这条边的两个端点之间形成一个环,为了让维持树的结构,我们要断开环上的一条边,而为了让得到的新生成树尽量小,于是我们就选择最大的一条边断开,但是为了保证严格次小,在这条边和最大边长度相同时,断开一条严格次大的边

    而从树上找两点之间的最大边和严格次大边,我们显然可以直接上树剖

    我们可以维护出每一个到其所在重链顶端的最大边和严格次大边,之后直接倍增往上跳就可以了

    直到跳到两个点在同一条重链上的时候,没有办法在像之前那样做了,于是直接用线段树来查询

    单次做的复杂度还是(O(logn))

    但是树剖是出了名的小常数,常数大的线段树也只做了一次查询,于是效率非常喜人,在我人傻常数大的情况下依旧跑到了最优解第二

    代码

    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #include<algorithm>
    #include<bitset>
    #define mp std::make_pair
    #define re register
    #define LL long long
    #define maxn 100005
    #define max(a,b) ((a)>(b)?(a):(b))
    #define min(a,b) ((a)<(b)?(a):(b))
    #define k1 first
    #define k2 second
    typedef std::pair<int,int> pii;
    struct node
    {
    	int v,nxt,w;
    }e[maxn<<1],a[maxn*3];
    std::bitset<maxn*3> ff;
    int l[maxn<<2],r[maxn<<2],t1[maxn<<2],t2[maxn<<2];
    int head[maxn],deep[maxn],fa[maxn],tot[maxn],to[maxn],b[maxn];
    int top[maxn],f[maxn],son[maxn],sum[maxn],d1[maxn],d2[maxn],pre[maxn];
    int n,m,num,_;
    LL cnt;
    void dfs1(int r)
    {
    	sum[r]=1;
    	int maxx=-1;
    	for(re int i=head[r];i;i=e[i].nxt)
    	if(!deep[e[i].v])
    	{
    		deep[e[i].v]=deep[r]+1;
    		pre[e[i].v]=pre[r]+e[i].w;
    		f[e[i].v]=r;
    		dfs1(e[i].v);
    		sum[r]+=sum[e[i].v];
    		if(sum[e[i].v]>maxx) maxx=sum[e[i].v],son[r]=e[i].v;
    	}
    }
    void dfs2(int r,int topf)
    {
    	top[r]=topf;
    	to[r]=++_;
    	b[_]=pre[r]-pre[f[r]];
    	if(r!=topf)
    	{
    		if(pre[r]-pre[f[r]]>d1[f[r]]) d2[r]=d1[f[r]];
    			else if(pre[r]-pre[f[r]]<d1[f[r]]) d2[r]=max(d2[r],pre[r]-pre[f[r]]);
    				else d2[r]=d2[f[r]];
    		d1[r]=max(d1[f[r]],pre[r]-pre[f[r]]);
    	}
    	if(!son[r]) return;
    	dfs2(son[r],topf);
    	for(re int i=head[r];i;i=e[i].nxt)
    	if(deep[e[i].v]>deep[r]&&son[r]!=e[i].v) d1[e[i].v]=-99,d2[e[i].v]=-100,dfs2(e[i].v,e[i].v);
    }
    inline int find(int x)
    {
    	if(fa[x]==x) return x;
    	return fa[x]=find(fa[x]);
    }
    inline int read()
    {
    	char c=getchar();
    	int x=0;
    	while(c<'0'||c>'9') c=getchar();
    	while(c>='0'&&c<='9')
    		x=(x<<3)+(x<<1)+c-48,c=getchar();
    	return x;
    }
    inline void add_edge(int x,int y,int z)
    {
    	e[++num].v=y;
    	e[num].w=z;
    	e[num].nxt=head[x];
    	head[x]=num;
    }
    inline int cmp(node K,node M)
    {
    	return K.w<M.w;
    }
    inline void swap(int &a,int &b) {a^=b,b^=a,a^=b;}
    void build(int x,int y,int i)
    {
    	l[i]=x;r[i]=y;
    	if(x==y)
    	{
    		t1[i]=b[x];
    		return;
    	}
    	int mid=x+y>>1;
    	build(x,mid,i<<1),build(mid+1,y,i<<1|1);
    	t1[i]=max(t1[i<<1|1],t1[i<<1]);
    	if(t1[i<<1|1]>t1[i<<1]) t2[i]=max(t2[i<<1|1],t1[i<<1]);
    		else if(t1[i<<1]>t1[i<<1|1]) t2[i]=max(t2[i<<1],t1[i<<1|1]);
    			else t2[i]=max(t2[i<<1|1],t2[i<<1]);
    }
    pii query(int x,int y,int i)
    {
    	if(x<=l[i]&&y>=r[i]) return mp(t1[i],t2[i]);
    	int mid=l[i]+r[i]>>1;
    	if(y<=mid) return query(x,y,i<<1);
    	if(x>mid) return query(x,y,i<<1|1);
    	pii lson=query(x,y,i<<1),rson=query(x,y,i<<1|1);
    	pii now;
    	now.k1=max(lson.k1,rson.k1);
    	if(lson.k1>rson.k1) now.k2=max(lson.k2,rson.k1);
    		else if(lson.k1<rson.k1) now.k2=max(lson.k1,rson.k2);
    			else now.k2=max(rson.k2,lson.k2);
    	return now;
    }
    int main()
    {
    	n=read(),m=read();
    	for(re int i=1;i<=m;++i)
    		a[i].v=read(),a[i].nxt=read(),a[i].w=read();
    	std::sort(a+1,a+m+1,cmp);
    	for(re int i=1;i<=n;++i) fa[i]=i,tot[i]=1;
    	int K=0;
    	for(re int i=1;i<=m;++i)
    	{
    		int xx=find(a[i].v);
    		int yy=find(a[i].nxt);
    		if(xx!=yy)
    		{
    			K++;
    			ff[i]=1;
    			add_edge(a[i].v,a[i].nxt,a[i].w);
    			add_edge(a[i].nxt,a[i].v,a[i].w);
    			if(tot[xx]>tot[yy]) fa[yy]=xx,tot[xx]+=tot[yy];
    			else fa[xx]=yy,tot[yy]+=tot[xx];
    			cnt+=a[i].w;
    		}
    		if(K==n-1) break;
    	}
    	deep[1]=1;
    	dfs1(1);
    	d1[1]=-99,d2[1]=-100;
    	dfs2(1,1);
    	build(1,n,1);
    	LL ans=9999999999999999;
    	for(re int i=m;i;--i)
    	if(!ff[i])
    	{
    		int m1=0,m2=-1;
    		int x=a[i].v;
    		int y=a[i].nxt;
    		while(top[x]!=top[y])
    		{
    			if(deep[top[x]]<deep[top[y]]) swap(x,y);
    			if(d1[x]<m1) m2=max(m2,d1[x]);
    				else if(d1[x]>m1) m2=m1;
    					else m2=max(m2,d2[x]);
    			m1=max(m1,d1[x]);
    			if(pre[x]-pre[f[x]]<m1) m2=max(m2,pre[x]-pre[f[x]]);
    				else if(pre[x]-pre[f[x]]>m1) m2=m1;
    			m1=max(m1,pre[x]-pre[f[x]]);
    			x=f[top[x]];
    		}
    		if(x!=y)
    		{
    			if(deep[x]>deep[y]) swap(x,y);
    			pii now=query(to[x]+1,to[y],1);
    			if(now.k1>m1) m2=m1;
    				else if(now.k1<m1) m2=max(m2,now.k1);
    					else m2=max(m2,now.k2);
    			m1=max(m1,now.k1);
    		}
    		if(a[i].w<m1) continue;
    		if(a[i].w>m1) ans=min(ans,cnt+a[i].w-m1);
    		if(a[i].w==m1&&m2) ans=min(ans,cnt+a[i].w-m2);
    	}
    	std::cout<<ans;
    	return 0;
    }
    
  • 相关阅读:
    帝国 标签模板 使用程序代码 去除html标记 并 截取字符串
    iis6 伪静态 iis配置方法 【图解】
    您来自的链接不存在 帝国CMS
    帝国cms Warning: Cannot modify header information headers already sent by...错误【解决方法】
    .fr域名注册 51元注册.fr域名
    帝国网站管理系统 恢复栏目目录 建立目录不成功!请检查目录权限 Godaddy Windows 主机
    星外虚拟主机管理平台 开通数据库 出现Microsoft OLE DB Provider for SQL Server 错误 '8004' 从字符串向 datetime 转换失败
    ASP.NET 自定义控件学习研究
    CSS层叠样式表之CSS解析机制的优先级
    ASP.NET程序员工作面试网络收藏夹
  • 原文地址:https://www.cnblogs.com/asuldb/p/10206196.html
Copyright © 2011-2022 走看看