LCA&最小生成树
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&最小生成树的更多相关文章
- BZOJ3732Network——kruskal重构树+倍增+LCA/最小生成树+倍增
题目描述 给你N个点的无向图 (1 <= N <= 15,000),记为:1…N. 图中有M条边 (1 <= M <= 30,000) ,第j条边的长度为: d_j ( 1 & ...
- uva11354 LCA+最小生成树+dp
源自大白书 题意 有n座城市通过m条双向道路相连,每条道路都有一个危险系数.你的任务是回答若干个询问,每个询问包含一个起点s和一个终点t,要求找到一条从s到t的路,使得途径所有的边的大最大危险系数最小 ...
- The Shortest Statement(Educational Codeforces Round 51 (Rated for Div.2)+最短路+LCA+最小生成树)
题目链接 传送门 题面 题意 给你一张有\(n\)个点\(m\)条边的联通图(其中\(m\leq n+20)\),\(q\)次查询,每次询问\(u\)与\(v\)之间的最短路. 思路 由于边数最多只比 ...
- 洛谷 P1967 货车运输 LCA + 最小生成树
两点之间边权最大值的最小值一定在图的最小生成树中取到. 求出最小生成树,进行倍增即可. Code: #include<cstdio> #include<algorithm> u ...
- 【Diary】
[写日记是好习惯] 前记 很随意的日记.想什么写什么,没有限制. 希望以后看到曾经,努力的自己比摸鱼的自己多. 2019.3 2019.3.29 第24次请假打卡 xzh:那些理科男以后都会当IT工作 ...
- bzoj3732: Network--kruskal最小生成树+LCA
这是一道写起来比较顺手的题目 没有各种奇怪的细节,基本就是Kruskal和倍增LCA的模板.. 题目大意:对于一个无向带权图,询问两点之间一条路,使得这条路上的最长边最小,输出最小最长边的的值 那么既 ...
- BZOJ3732 解析报告//LCA,最小生成树
3732: Network 题目描述 给你N个点的无向图 (1 <= N <= 15,000),记为:1…N. 图中有M条边 (1 <= M <= 30,000) ,第j条边的 ...
- Luogu 2245 星际导航(最小生成树,最近公共祖先LCA,并查集)
Luogu 2245 星际导航(最小生成树,最近公共祖先LCA,并查集) Description sideman做好了回到Gliese 星球的硬件准备,但是sideman的导航系统还没有完全设计好.为 ...
- 洛谷P4180 [Beijing2010组队]次小生成树Tree(最小生成树,LCT,主席树,倍增LCA,倍增,树链剖分)
洛谷题目传送门 %%%TPLY巨佬和ysner巨佬%%% 他们的题解 思路分析 具体思路都在各位巨佬的题解中.这题做法挺多的,我就不对每个都详细讲了,泛泛而谈吧. 大多数算法都要用kruskal把最小 ...
随机推荐
- JsonCpp 的使用
JSON全称为JavaScript ObjectNotation,它是一种轻量级的数据交换格式,易于阅读.编写.解析.jsoncpp是c++解析JSON串常用的解析库之一. jsoncpp中主要的类: ...
- 【Android】Eclipse性能优化,快捷方式,文档注释
快捷方式 方法注释的快捷键:ALT + SHIFT +J 格式化:Ctrl+Shift+F 把当前选中的文本全部变味大写:Ctrl+Shift+X 把当前选中的文本全部变为小写:Ctrl+Shift+ ...
- Android Launcher分析和修改5——HotSeat分析
今天主要是分析一下Launcher里面的快捷方式导航条——HotSeat,一般我们使用手机底下都会有这个导航条,但是如果4.0的Launcher放到平板电脑里面运行,默认是没有HotSeat的,刚好我 ...
- Android 自动化测试——Monkey测试
Android自带了很多方便的测试工具和方法,包括我们常用的单元测试.Robotium测试.Monkey测试.MonkeyRunner测试.senevent模拟等.这些方法对于我们编写高质量的APP十 ...
- 模仿Semaphore自定义自己的 信号量
简介 这里模仿Semaphore,自定义自己的信号量,利用AQS共享模式 1.MySemaphore.java package com.jacky; import java.util.concurre ...
- Error: parent directory is world writable but not sticky
在本地安装pyenv的时候,出现了如下的报错: ➜ brew install pyenv ==> Downloading https://github.com/yyuu/pyenv/archiv ...
- Guava Lists.transform踩坑小记<转>
1.问题提出 1.前段时间在项目中用到Lists.transform返回的List,在对该list修改后发现修改并没有反映在结果里,研究源码后发现问题还挺大.下面通过单步调试的结果来查看Guava L ...
- JVM内存管理及垃圾回收【转】
很多Java面试的时候,都会问到有关Java垃圾回收的问题,提到垃圾回收肯定要涉及到JVM内存管理机制,Java语言的执行效率一直被C.C++程序员所嘲笑,其实,事实就是这样,Java在执行效率方面确 ...
- 为app录制展示gif
已同步更新至个人blog:http://dxjia.cn/2015/07/make-gif-for-app/ 在github上好多不错的开源项目展示demo的时候,都是采用了一个gif图片,很生动具体 ...
- Oracle Enterprise Linux 6.4 下挂载ISCSI 设备
Oracle Enterprise Linux 6.4 下挂载ISCSI 设备一.发现① 要求安装iscsi客户端软件 yum install iscsi-initiator-utils ② 发现 ...