【【模板】严格次小生成树[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;
}
【【模板】严格次小生成树[BJWC2010]】的更多相关文章
- P4180 【模板】严格次小生成树[BJWC2010]
P4180 [模板]严格次小生成树[BJWC2010] 倍增(LCA)+最小生成树 施工队挖断学校光缆导致断网1天(大雾) 考虑直接枚举不在最小生成树上的边.但是边权可能与最小生成树上的边相等,这样删 ...
- 【洛谷】4180:【模板】严格次小生成树[BJWC2010]【链剖】【线段树维护最大、严格次大值】
P4180 [模板]严格次小生成树[BJWC2010] 题目描述 小C最近学了很多最小生成树的算法,Prim算法.Kurskal算法.消圈算法等等.正当小C洋洋得意之时,小P又来泼小C冷水了.小P说, ...
- 「LuoguP4180」 【模板】严格次小生成树[BJWC2010](倍增 LCA Kruscal
题目描述 小C最近学了很多最小生成树的算法,Prim算法.Kurskal算法.消圈算法等等.正当小C洋洋得意之时,小P又来泼小C冷水了.小P说,让小C求出一个无向图的次小生成树,而且这个次小生成树还得 ...
- Luogu P4180 【模板】严格次小生成树[BJWC2010]
P4180 [模板]严格次小生成树[BJWC2010] 题意 题目描述 小\(C\)最近学了很多最小生成树的算法,\(Prim\)算法.\(Kurskal\)算法.消圈算法等等.正当小\(C\)洋洋得 ...
- 洛谷 P4180 【模板】严格次小生成树[BJWC2010]【次小生成树】
严格次小生成树模板 算法流程: 先用克鲁斯卡尔求最小生成树,然后给这个最小生成树树剖一下,维护边权转点权,维护最大值和严格次大值. 然后枚举没有被选入最小生成树的边,在最小生成树上查一下这条边的两端点 ...
- 【luogu P4180 严格次小生成树[BJWC2010]】 模板
题目链接:https://www.luogu.org/problemnew/show/P4180 这个题卡树剖.记得开O2. 这个题inf要到1e18. 定理:次小生成树和最小生成树差距只有在一条边上 ...
- 【洛谷 P4180】【模板】严格次小生成树[BJWC2010](倍增)
题目链接 题意如题. 这题作为我们KS图论的T4,我直接打了个很暴力的暴力,骗了20分.. 当然,我们KS里的数据范围远不及这题. 这题我debug了整整一个晚上还没debug出来,第二天早上眼前一亮 ...
- 「BJWC2010」模板严格次小生成树
题目描述 小 \(C\) 最近学了很多最小生成树的算法,\(Prim\) 算法.\(Kruskal\) 算法.消圈算法等等.正当小\(C\)洋洋得意之时,小\(P\)又来泼小\(C\)冷水了.小\(P ...
- P4180 严格次小生成树[BJWC2010] Kruskal,倍增
题目链接\(Click\) \(Here\). 题意就是要求一个图的严格次小生成树.以前被题面吓到了没敢做,写了一下发现并不难. 既然要考虑次小我们就先考虑最小.可以感性理解到一定有一种次小生成树,可 ...
随机推荐
- C# 空合并运算符 ??
C#语言中,??运算符称为空合并运算符: a??b形式的空合并表达式要求a为可以为null的类型或引用类型.如果a为非null,则a??b的结果为a:否则,结果为b.仅当a为null时,该操作才计算b ...
- vertical-align属性baseline(转)
图7-34 文字和图片内容默认垂直对齐方式为基线对齐 上一小节讲解了行高与单行纯文字的垂直居中,而如果行内含有图片和文字,在浏览器内浏览时,读者可以发现文字和图片在垂直方向并不是沿中线居中,而是沿基线 ...
- ubuntu 配置dns访问外网
我新建了一个虚拟机后采用的net模式 一 先配置虚拟机ip使其能在局域网内通信 1.vmware 编辑->虚拟网络编辑器 可以看到网关.掩码等信息 可以看到我们配置的ip应该在192.168.1 ...
- RFC1939 POP3协议 中文版 (转载)
1.简介 对于在网络上的比较小的结点,支持消息传输系统(MTS)是不实际的.例如,一台工作站可能不具有充足的资源允许SMTP服务器和相当的本地邮件传送系统保持序驻留,并持续运行.同样的,将一台个人 ...
- C#学习笔记(基础知识回顾)之值类型与引用类型转换(装箱和拆箱)
一:值类型和引用类型的含义参考前一篇文章 C#学习笔记(基础知识回顾)之值类型和引用类型 1.1,C#数据类型分为在栈上分配内存的值类型和在托管堆上分配内存的引用类型.如果int只不过是栈上的一个4字 ...
- 最小树形图--朱刘算法([JSOI2008]小店购物)
题面 luogu Sol 首先设一个 \(0\) 号点,向所有点连边,表示初始价值 显然这个图的一个 \(0\) 为根的最小有向生成树的边权和就是每个买一次的最小价值 再买就一定能优惠(包含 \(0\ ...
- 关于电脑宽带显示连接 qq可以登录 但是无法上网的问题
---恢复内容开始--- 大家都遇到过这种情况吧,右下角显示网络已连接,但就是上不了网,解决的办法大都是什么,打开网络与共享中心设置什么协议什么的,当然,这些有可能是有用的,但是有一些不管怎么设置协议 ...
- 将本地项目放到GitHub上托管并展示
忽然知道自己写的项目效果可以放到网上让别人看到之后,就已经迫不及待了.不墨迹,先去了解GitHub得知,它很强(牛逼),我理解的是这是一个托管平台,可以把自己本地的项目通过git放到上面,你需要新建一 ...
- 【源代码R3】移植一份LARGE_INTEGER转时间的代码
本代码来自ReactOS-0.4.0\lib\rtl\time.c中的函数RtlTimeToTimeFields(IN PLARGE_INTEGER Time, OUT PTIME_FIELDS Ti ...
- 基于openlayers2军事标绘,开源
1.其实各GIS公司.网络上 都会有提供 军事标绘的功能,如arcgis 的,超图的.mapgis的:但大多数是非开源.且收费的.2.在这里要感谢超图,超图开源了标绘扩展符号库,我这里使用的就是超图的 ...