LCA 经常被用来使用。比如询问树两点之间的距离。

比如树上差分 都是经常被使用的类型。有的时候倍增求LCA的同时还可以优化算法。

这道题呢 求一个严格的最小生成树,当然如果不严格的话如果有重边那么就和原来一样喽。

这里推广一些关于最小生成树的定理 在图中 最小生成树边权一定是一定的。

那么由此可以推出不同的最小生成树也就是边不同但是他们被连在图中的边权一定相等。

所以上述结论和这道题没什么关系 关键是严格的次小生成树 。

我们可以加边 来完成这整个操作,考虑到对于每一条边造成的影响还是这两点之间的最短距离的影响。仔细想就知道了。

那么影响转化成了他们到LCA这些边的影响,LCA之外的边可就没什么事了。

我们只需要求出他们到LCA的最长边有多大即可。如果相等了那么没用了么?此时必须要维护一个次小的边权已被不时只需。

建模成功! 我们把问题成功转换成了 求两点之间到LCA之间的最大边权 严格次大边权。

LCA 可以tarjan,复杂度非常优秀可是考虑到 一些问题,求不出边权 先求出祖先再往上爬不就好了?

这样写有些 复杂度nm 并不能通过此题。考虑倍增求出LCA

在往上跳跃的时候我们维护一个最大值边权和次大值边权即可。复杂度mlgn

//#include<bits/stdc++.h>
#include<iostream>
#include<cstdio>
#include<iomanip>
#include<cstring>
#include<string>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#include<cctype>
#include<utility>
#include<set>
#include<bitset>
#include<queue>
#include<stack>
#include<deque>
#include<map>
#include<vector>
#include<ctime>
#define ll long long
#define INF 2147483646
#define z(i) t[i].z
using namespace std;
char buf[<<],*fs,*ft;
inline char getc()
{
return (fs==ft&&(ft=(fs=buf)+fread(buf,,<<,stdin),fs==ft))?:*fs++;
}
inline ll read()
{
ll x=,f=;char ch=getc();
while(ch<''||ch>''){if(ch=='-')f=-;ch=getc();}
while(ch>=''&&ch<=''){x=x*+ch-'';ch=getc();}
return x*f;
}
inline void put(ll x)
{
x<?putchar('-'),x=-x:;
ll num=;char ch[];
while(x)ch[++num]=x%+'',x/=;
num==?putchar(''):;
while(num)putchar(ch[num--]);
putchar(' ');return;
}
const ll MAXN=,maxn=;
ll n,m,sum,cnt,T,maxx,maxx1,minn;
ll lin[MAXN<<],nex[MAXN<<],ver[MAXN<<],e[MAXN<<],len=;
ll clin[MAXN<<],cnex[MAXN<<],cver[MAXN<<],ce[MAXN<<],clen=;
ll dis[maxn],depth[maxn],vis[maxn],f[maxn][],g[maxn][][];//f[i][k]表示i节点向上爬2^k个节点
//g[i][k][0/1]表示i节点向上爬2^k个节点之中的最大值 严格次大值
priority_queue<pair<ll,pair<ll,ll> > > q;
inline ll max(ll x,ll y){return x>y?x:y;}
inline ll min(ll x,ll y){return x>y?y:x;}
inline void swap(ll &x,ll &y){ll t;t=x;x=y;y=t;}
struct wy{ll x,y,z;}t[MAXN];
void add(ll x,ll y,ll z)
{
ver[++len]=y;
nex[len]=lin[x];
lin[x]=len;
e[len]=z;
}
void cadd(ll x,ll y,ll z)
{
cver[++clen]=y;
cnex[clen]=clin[x];
clin[x]=clen;
ce[clen]=z;
}
void prim()
{
for(ll i=;i<=n;i++)dis[i]=INF;
memset(vis,,sizeof(vis));
dis[]=;ll flag=;
q.push(make_pair(dis[],make_pair(,)));
while(q.size())
{
ll te=q.top().second.first;
ll yy=q.top().second.second;
q.pop();
if(vis[te]==)continue;
vis[te]=;sum+=dis[te];
++flag;if(flag!=)cadd(te,yy,dis[te]),cadd(yy,te,dis[te]);
for(ll i=lin[te];i;i=nex[i])
{
ll tn=ver[i];
if(vis[tn]==)continue;
if(dis[tn]>e[i])
{
dis[tn]=e[i];
q.push(make_pair(-dis[tn],make_pair(tn,te)));
}
}
}
}
void dfs(ll x,ll fa)
{
depth[x]=depth[fa]+;
f[x][]=fa;
for(ll i=;i<=T;++i)
{
f[x][i]=f[f[x][i-]][i-];
g[x][i][]=max(g[x][i-][],g[f[x][i-]][i-][]);
if(g[x][i-][]==g[f[x][i-]][i-][])g[x][i][]=max(g[x][i-][],g[f[x][i-]][i-][]);
if(g[x][i-][]>g[f[x][i-]][i-][])g[x][i][]=max(g[x][i-][],g[f[x][i-]][i-][]);
if(g[x][i-][]<g[f[x][i-]][i-][])g[x][i][]=max(g[x][i-][],g[f[x][i-]][i-][]);
}
for(ll i=clin[x];i;i=cnex[i])
{
ll tn=cver[i];
if(tn==fa)continue;
g[tn][][]=ce[i];
g[tn][][]=-INF;
dfs(tn,x);
}
}
void lca(ll x,ll y)
{
if(depth[x]>depth[y])swap(x,y);//y>x
for(ll i=T;i>=;--i)
{
if(depth[f[y][i]]>=depth[x])
{
if(maxx>g[y][i][])maxx1=max(maxx1,g[y][i][]);
if(maxx<g[y][i][])maxx1=max(maxx,maxx1);
maxx=max(maxx,g[y][i][]);
maxx1=max(maxx1,g[y][i][]);
y=f[y][i];
}
}
if(x==y)return;
for(ll i=T;i>=;--i)
{
if(f[x][i]!=f[y][i])
{
if(maxx>g[y][i][])maxx1=max(maxx1,g[y][i][]);
if(maxx<g[y][i][])maxx1=max(maxx,maxx1);
if(maxx>g[x][i][])maxx1=max(maxx1,g[x][i][]);
if(maxx<g[x][i][])maxx1=max(maxx,maxx1);
maxx=max(maxx,g[x][i][]);
maxx1=max(maxx1,g[x][i][]);
maxx=max(maxx,g[y][i][]);
maxx1=max(maxx1,g[y][i][]);
x=f[x][i];y=f[y][i];
}
}
if(maxx>g[y][][])maxx1=max(maxx1,g[y][][]);
if(maxx<g[y][][])maxx1=max(maxx,maxx1);
if(maxx>g[x][][])maxx1=max(maxx1,g[x][][]);
if(maxx<g[x][][])maxx1=max(maxx,maxx1);
maxx=max(maxx,g[x][][]);
maxx=max(maxx,g[y][][]);
return;
}
int main()
{
//freopen("1.in","r",stdin);
n=read();m=read();
for(ll i=;i<=m;++i)
{
ll x,y,z;
x=read();y=read();z=read();
t[i].x=x;t[i].y=y;z(i)=z;
add(x,y,z);add(y,x,z);
}
prim();
//put(sum);
T=(ll)(log(n*1.0)/log(*1.0))+;
//put(T);
dfs(,);minn=INF;
for(ll i=;i<=m;++i)
{
maxx=maxx1=-INF;
lca(t[i].x,t[i].y);
if(maxx==z(i))minn=min(minn,z(i)-maxx1);
else minn=min(minn,z(i)-maxx);
}
put(sum+minn);
return ;
}

这道题呢 很有意思但是我并没有观察到问题的特异性 。

可能是 写题的时候大脑太累了 不思考了,以后累的时候一定要休息一会效率不但高而且很敏锐的就可以破解问题。

注意 最最小生成树的个数 每个最小生成树相同边权的个数一定是相同的,因为考虑如果有一个更优的边权可以加到图中,我的最小生成树还是最小生成树么,

那如果是刚好有一条边让出来位置呢,那么我的最小生成树边权的相同边权的个数还是一定的。证毕。

那么 根据前面一道题我的废话 就可以得到一个算法了 前面的废话是一些点 被连在最小生成树上的边权一定是相等的。

也就是联通块每次都是一样的只不过点连到联通块的方式不太一样。那么既然n只有100 也就是边至多99条。

且每条边权值只有10条 那么 爆搜在最小生成树上的每一条边即可。

复杂度 2^n*n 多么完美啊,加上玄学剪枝 直接完爆正解!!!

//#include<bits/stdc++.h>
#include<iostream>
#include<cstdio>
#include<iomanip>
#include<cstring>
#include<string>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#include<cctype>
#include<utility>
#include<set>
#include<bitset>
#include<queue>
#include<stack>
#include<deque>
#include<map>
#include<vector>
#include<ctime>
#define ll long long
#define INF 2147483647
#define z(i) t[i].z
#define x(i) t[i].x
#define y(i) t[i].y
#define mod 31011
using namespace std;
char buf[<<],*fs,*ft;
inline char getc()
{
return (fs==ft&&(ft=(fs=buf)+fread(buf,,<<,stdin),fs==ft))?:*fs++;
}
inline int read()
{
int x=,f=;char ch=getc();
while(ch<''||ch>''){if(ch=='-')f=-;ch=getc();}
while(ch>=''&&ch<=''){x=x*+ch-'';ch=getc();}
return x*f;
}
inline void put(int x)
{
x<?putchar('-'),x=-x:;
int num=;char ch[];
while(x)ch[++num]=x%+'',x/=;
num==?putchar(''):;
while(num)putchar(ch[num--]);
putchar(' ');return;
}
const int MAXN=;
int n,m,ans,cnt,sum=,w;
int f[MAXN];
struct wy
{
int x,y,z;
friend int operator <(const wy &p,const wy &u)
{
return p.z<u.z;
}
}t[MAXN];
struct wy1{int x,y,k,v;}b[MAXN];
int gf(int x){return x==f[x]?x:f[x]=gf(f[x]);}
int getfather(int x){return x==f[x]?x:getfather(f[x]);}
void dfs(int x,int depth,int s,int k)
{
if(s+depth-x+<k)return;
if(s==k){ans++;return;}
if(x==depth+)return;
dfs(x+,depth,s,k);
int xx=getfather(t[x].x);
int yy=getfather(t[x].y);
if(xx!=yy)
{
f[xx]=yy;
dfs(x+,depth,s+,k);
f[xx]=xx;f[yy]=yy;
}
return;
}
int main()
{
//freopen("1.in","r",stdin);
n=read();m=read();
for(int i=;i<=m;++i)
{
x(i)=read();
y(i)=read();
z(i)=read();
}
for(int i=;i<=n;++i)f[i]=i;
sort(t+,t++m);
for(int i=;i<=m;++i)
{
if(i==)b[++cnt].x=i;
else if(z(i)!=z(i-))b[cnt].y=i-,b[++cnt].x=i;
int xx=gf(x(i));
int yy=gf(y(i));
if(xx!=yy)
{
f[xx]=yy;ans+=z(i);
++b[cnt].k;++w;
}
}
b[cnt].y=m;
if(w!=n-){put();return ;}
//put(cnt);
//put(ans);
//for(int i=1;i<=cnt;++i)put(b[i].k);
for(int i=;i<=n;++i)f[i]=i;
for(int i=;i<=cnt;++i)
{
if(b[i].k)
{
ans=;
dfs(b[i].x,b[i].y,,b[i].k);
sum=(sum*(ans%mod))%mod;
for(int j=b[i].x;j<=b[i].y;++j)
{
int xx=gf(t[j].x);
int yy=gf(t[j].y);
f[xx]=yy;
}
}
}
put(sum);
return ;
}

LCA&最小生成树的更多相关文章

  1. BZOJ3732Network——kruskal重构树+倍增+LCA/最小生成树+倍增

    题目描述 给你N个点的无向图 (1 <= N <= 15,000),记为:1…N. 图中有M条边 (1 <= M <= 30,000) ,第j条边的长度为: d_j ( 1 & ...

  2. uva11354 LCA+最小生成树+dp

    源自大白书 题意 有n座城市通过m条双向道路相连,每条道路都有一个危险系数.你的任务是回答若干个询问,每个询问包含一个起点s和一个终点t,要求找到一条从s到t的路,使得途径所有的边的大最大危险系数最小 ...

  3. The Shortest Statement(Educational Codeforces Round 51 (Rated for Div.2)+最短路+LCA+最小生成树)

    题目链接 传送门 题面 题意 给你一张有\(n\)个点\(m\)条边的联通图(其中\(m\leq n+20)\),\(q\)次查询,每次询问\(u\)与\(v\)之间的最短路. 思路 由于边数最多只比 ...

  4. 洛谷 P1967 货车运输 LCA + 最小生成树

    两点之间边权最大值的最小值一定在图的最小生成树中取到. 求出最小生成树,进行倍增即可. Code: #include<cstdio> #include<algorithm> u ...

  5. 【Diary】

    [写日记是好习惯] 前记 很随意的日记.想什么写什么,没有限制. 希望以后看到曾经,努力的自己比摸鱼的自己多. 2019.3 2019.3.29 第24次请假打卡 xzh:那些理科男以后都会当IT工作 ...

  6. bzoj3732: Network--kruskal最小生成树+LCA

    这是一道写起来比较顺手的题目 没有各种奇怪的细节,基本就是Kruskal和倍增LCA的模板.. 题目大意:对于一个无向带权图,询问两点之间一条路,使得这条路上的最长边最小,输出最小最长边的的值 那么既 ...

  7. BZOJ3732 解析报告//LCA,最小生成树

    3732: Network 题目描述 给你N个点的无向图 (1 <= N <= 15,000),记为:1…N. 图中有M条边 (1 <= M <= 30,000) ,第j条边的 ...

  8. Luogu 2245 星际导航(最小生成树,最近公共祖先LCA,并查集)

    Luogu 2245 星际导航(最小生成树,最近公共祖先LCA,并查集) Description sideman做好了回到Gliese 星球的硬件准备,但是sideman的导航系统还没有完全设计好.为 ...

  9. 洛谷P4180 [Beijing2010组队]次小生成树Tree(最小生成树,LCT,主席树,倍增LCA,倍增,树链剖分)

    洛谷题目传送门 %%%TPLY巨佬和ysner巨佬%%% 他们的题解 思路分析 具体思路都在各位巨佬的题解中.这题做法挺多的,我就不对每个都详细讲了,泛泛而谈吧. 大多数算法都要用kruskal把最小 ...

随机推荐

  1. git 命令常用总结

    详细git教程可参考:http://www.liaoxuefeng.com/wiki/0013739516305929606dd18361248578c67b8067c8c017b000 基础命令 用 ...

  2. mysql 5.7 学习

    MySQL5.7 添加用户.删除用户与授权   mysql -uroot -proot MySQL5.7 mysql.user表没有password字段改 authentication_string: ...

  3. Future 模式简介

    简介 Future 模式是多线程开发中的一种常见设计模式,它的核心思想是异步调用. 比如我们在网上购物,付款后就会产生一个订单,之后你该干嘛干嘛,快递小哥会上门送货,而不必像在超市结账那样,付款后要等 ...

  4. Java如何检查端口是否被使用?

    在Java编程中,如何扫描打开的端口(是否被使用)? 以下示例显示如何通过创建 Socket 对象来检查主机上打开或正在使用的端口(相当于一个简单的端口扫描器). package com.yiibai ...

  5. oracle 11g 使用物化视图远程增量刷新数据

    ① 源数据库建立物化视图日志 drop MATERIALIZED VIEW LOG ON ORG_BASEINFO/ CREATE MATERIALIZED VIEW LOG ON ORG_BASEI ...

  6. WebView与 JS 交互方式

    前言 现在很多App里都内置了Web网页(Hybrid App),比如说很多电商平台,淘宝.京东.聚划算等等,如下图 上述功能是由Android的WebView实现的,其中涉及到Android客户端与 ...

  7. DedeCMS织梦文章页图片地址为绝对路径实现方法

    {dede:field.body function='replaceurl(@me)'/} 余斗博客改版后增加了一个m站点即手机站点,用二级域名实现,在做手机站的过程中发现一个问题,手机站和pc站都是 ...

  8. [Tensorflow] Cookbook - CNN

    Convolutional Neural Networks (CNNs) are responsible for the major breakthroughs in image recognitio ...

  9. Use a load-balancer as a first row of defense against DDOS

    We’ve seen recently more and more DOS and DDOS attacks. Some of them were very big, requiring thousa ...

  10. 解决在antd中使用 autoprefixer 9.4.5 会抛出错误 Replace text-decoration-skip: ink to text-decoration-skip-ink: auto, because spec had been changed 的问题

    其实这个和antd的版本有关系,只需要把antd的版本升级到3.12.4就可以了 yarn add antd@ --save 记得重新运行一下项目