洛咕P4180 严格次小生成树
鸽了很久的一道题(?)貌似是去年NOIP前听的emm...
首先我们分析一下最小生成树的性质
我们kruskal建树的时候呢是从小到大贪心加的边,这个的证明用到拟阵。(我太菜了不会)
首先我们不存在连接非树边比当前优的情况。
emm我们好像也就用这一条性质就够了。
步入正题
根据我们刚刚说的性质,我们可以枚举每一条边,使它和原来的树边形成一个环,然后我们需要求环上最大值,让我们的非树边替换掉这个边形成新的生成树。很显然这条边不会小于最大边,因为如果小于最大边的话,我们用这条边替换掉最大边会形成更小的生成树。如果这条边刚好等于最大边的话,那么我们求出来的不是严格次小生成树,而是非严格,因为两棵树的边权和相等。那么如果我们的非树边和最大值相等我们就不考虑了嘛(?)很显然不可以,因为我们可能有非树边-次大边更优的情况。所以我们维护链上最大值和次大值就可以啦。
Step1:建立最小生成树(这个很显然嘛,既然要求严格次小生成树,你肯定得先有棵树嘛)
Step2:处理生成树信息。
Step3:枚举每条非树边更新答案。
我来解释一下处理生成树信息都有啥。我们根据刚刚说的,我们需要维护链上最大值和次大值以及求LCA。这一步可以使用许多做法。我用的是倍增,然后树链剖分和LCT都是可以维护的。我才不想写LCT呢(傲娇脸)
容易错的地方的话我们一定要注意维护的次大值要严格小于最大值。
然后就到更新答案了。我们枚举的非树边有两种可能,横叉边or返祖边。分别讨论一下环的形态求链上比它严格小的最大值就可以了。
竟然1Abook思议
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#define maxn 101000
#define maxm 301000
#define lgn 18
#define ll long long
#define inf 2002122520021225ll
using namespace std;
int f[maxn][lgn+2],mx[maxn][lgn+2],sc[maxn][lgn+2];
struct edge{int u,v,val;}e[maxm];
struct Edge{int to,lt,val;}E[maxn<<1];
int in[maxn],cnt,dep[maxn];bool used[maxm];
bool cmp(edge a,edge b){return a.val<b.val;}
int fa[maxn],n,m;ll sum,ans;bool vis[maxn];
void add(int x,int y,int v)
{
E[++cnt].lt=in[x];E[cnt].to=y;E[cnt].val=v;in[x]=cnt;
E[++cnt].lt=in[y];E[cnt].to=x;E[cnt].val=v;in[y]=cnt;
}
int find(int x)
{
int i=x,j;
while(fa[x]!=x) x=fa[x];
while(i!=x) j=fa[i],fa[i]=x,i=j;
return x;
}
void dfs(int x)
{
vis[x]=1;
for(int i=1;i<=lgn;i++)
{
f[x][i]=f[f[x][i-1]][i-1];
mx[x][i]=max(mx[x][i-1],mx[f[x][i-1]][i-1]);
sc[x][i]=max(sc[x][i-1],sc[f[x][i-1]][i-1]);
if(mx[x][i-1]>mx[f[x][i-1]][i-1])
sc[x][i]=max(sc[x][i],mx[f[x][i-1]][i-1]);
else if(mx[x][i-1]<mx[f[x][i-1]][i-1])
sc[x][i]=max(sc[x][i],mx[x][i-1]);
}
for(int i=in[x];i;i=E[i].lt)
{
int v=E[i].to;
if(vis[v]) continue;
f[v][0]=x;mx[v][0]=E[i].val;dep[v]=dep[x]+1;dfs(v);
}
}
int jump(int x,int len)
{
for(int i=lgn;~i;i--)
if(len&(1<<i))
x=f[x][i];
return x;
}
int LCA(int x,int y)
{
if(dep[x]<dep[y]) swap(x,y);
x=jump(x,dep[x]-dep[y]);
if(x==y) return x;
for(int i=lgn;~i;i--)
if(f[x][i]^f[y][i])
x=f[x][i],y=f[y][i];
return f[x][0];
}
int getlink(int x,int len,int mm)
{
int qwq=0;
for(int i=lgn;~i;i--)
if(len&(1<<i))
{
if(mx[x][i]==mm) qwq=max(qwq,sc[x][i]);
else qwq=max(qwq,mx[x][i]);
x=f[x][i];
}
return qwq;
}
void kruskal()
{
int x,i,y,lca;
sort(e+1,e+m+1,cmp);
for(i=1;i<=n;i++) fa[i]=i;
for(i=1;i<=m;i++)
{
x=find(e[i].u),y=find(e[i].v);
if(x!=y)
{
fa[x]=y;ans+=(ll)e[i].val;
add(e[i].u,e[i].v,e[i].val);
used[i]=1;
}
}
dep[1]=1;dfs(1);sum=inf;
for(i=1;i<=m;i++)
{
if(!used[i])
{
x=e[i].u;y=e[i].v;
lca=LCA(x,y);
if(dep[x]<dep[y]) swap(x,y);
if(y==lca) sum=min(sum,ans-getlink(x,dep[x]-dep[lca],e[i].val)+e[i].val);
else sum=min(sum,ans-max(getlink(x,dep[x]-dep[lca],e[i].val),getlink(y,dep[y]-dep[lca],e[i].val))+e[i].val);
}
}
printf("%lld\n",sum);
}
int main()
{
int i;
scanf("%d%d",&n,&m);
for(i=1;i<=m;i++)
scanf("%d%d%d",&e[i].u,&e[i].v,&e[i].val);
kruskal();
return 0;
}
洛咕P4180 严格次小生成树的更多相关文章
- 洛谷P4180 [BJWC2010]次小生成树(最小生成树,LCT,主席树,倍增LCA,倍增,树链剖分)
洛谷题目传送门 %%%TPLY巨佬和ysner巨佬%%% 他们的题解 思路分析 具体思路都在各位巨佬的题解中.这题做法挺多的,我就不对每个都详细讲了,泛泛而谈吧. 大多数算法都要用kruskal把最小 ...
- bzoj 1977 洛谷P4180 严格次小生成树
Description: 给定一张N个节点M条边的无向图,求该图的严格次小生成树.设最小生成树边权之和为sum,那么严格次小生成树就是边权之和大于sum的最小的一个 Input: 第一行包含两个整数N ...
- 【luogu P4180 严格次小生成树[BJWC2010]】 模板
题目链接:https://www.luogu.org/problemnew/show/P4180 这个题卡树剖.记得开O2. 这个题inf要到1e18. 定理:次小生成树和最小生成树差距只有在一条边上 ...
- P4180 严格次小生成树[BJWC2010] Kruskal,倍增
题目链接\(Click\) \(Here\). 题意就是要求一个图的严格次小生成树.以前被题面吓到了没敢做,写了一下发现并不难. 既然要考虑次小我们就先考虑最小.可以感性理解到一定有一种次小生成树,可 ...
- 洛谷 P 4180 次小生成树
题目描述 小C最近学了很多最小生成树的算法,Prim算法.Kurskal算法.消圈算法等等.正当小C洋洋得意之时,小P又来泼小C冷水了.小P说,让小C求出一个无向图的次小生成树,而且这个次小生成树还得 ...
- BZOJ1977或洛谷4180 [BJWC2010]次小生成树
一道LCA+生成树 BZOJ原题链接 洛谷原题链接 细节挺多,我调了半天..累炸.. 回到正题,我们先求出随便一棵最小生成树(设边权和为\(s\)),然后扫描剩下所有边,设扫到的边的两端点为\(x,y ...
- 洛谷.4180.[模板]次小生成树Tree(Kruskal LCA 倍增)
题目链接 构建完MST后,枚举非树边(u,v,w),在树上u->v的路径中找一条权值最大的边(权为maxn),替换掉它 这样在 w=maxn 时显然不能满足严格次小.但是这个w可以替换掉树上严格 ...
- 【题解】洛谷P4180 [BJWC2010] 严格次小生成树(最小生成树+倍增求LCA)
洛谷P4180:https://www.luogu.org/problemnew/show/P4180 前言 这可以说是本蒟蒻打过最长的代码了 思路 先求出此图中的最小生成树 权值为tot 我们称这棵 ...
- 洛谷P4180【Beijing2010组队】次小生成树Tree
题目描述: 小C最近学了很多最小生成树的算法,Prim算法.Kurskal算法.消圈算法等等.正当小C洋洋得意之时,小P又来泼小C冷水了.小P说,让小C求出一个无向图的次小生成树,而且这个次小生成树还 ...
随机推荐
- 【转】Django 模板语法
转自:https://www.cnblogs.com/love9527/p/9077863.html Django 模板语法 一.模板 只要是在html里面有模板语法就不是html文件了,这样的文件就 ...
- [CSP-S模拟测试]:Merchant(二分答案)
题目描述 有$n$个物品,第$i$个物品有两个属性$k_i,b_i$,表示它在时刻$x$的价值为$k_i\times x+b_i$.当前处于时刻$0$,你可以选择不超过$m$个物品,使得存在某个整数时 ...
- 2019牛客暑期多校训练营(第九场)H Cutting Bamboos(主席树+二分)
题意:n个竹子,有高度,q次询问,询问之间是独立的,每次查询输入l,r,x,y代表砍区间[l,r]]内的竹子砍y次,最后一次要砍成0,每次砍掉的总长度相同,问第x次砍的高度是多少. 既然每次要求砍掉的 ...
- DHCP服务器怎么设置怎么启动
DHCP:动态主机配置协议,服务器用于为网络中的客户端自动分配IP地址.这种方法避免了由于手动配置IP地址导致的IP地址冲突问题,同时也减少了网络管理员的工作量. 工具/原料 在配置DHCP服务器时, ...
- MySQL-创建测试数据
简单的方法(每次增加一倍): insert into tb_user(f_id, f_username) select rand(), f_username from tb_user
- Linux运维工程师需掌握的技能
笔者是运维工程师,对Linux方面有点心得,现在说一下需要掌握哪方面的工具吧.说到工具,在行外可以说是技能,在行内我们一般称之为工具,就是运维必须要掌握的工具.我就大概列出这几方面,这样入门就基本没有 ...
- sql 优化建议
1.对查询进行优化,要尽量避免全表扫描,首先应考虑在 where 及 order by 涉及的列上建立索引. 2.应尽量避免在 where 子句中对字段进行 null 值判断,否则将导致引擎放弃使用索 ...
- java web项目启动加载顺序
转载:https://www.cnblogs.com/writeLessDoMore/p/6935524.html web.xml加载过程(步骤): 1.启动WEB项目的时候,容器(如:T ...
- 安全体系建设-OWASP
OWASP Checklist Spiders, Robots and Crawlers IG- Search Engine Discovery/Reconnaissance IG- Identify ...
- bfs(双向bfs加三维数组)
http://acm.hdu.edu.cn/showproblem.php?pid=2612 Find a way Time Limit: 3000/1000 MS (Java/Others) ...