倍增lca板子洛谷P3379

 #include<cstdio>
struct E
{
int to,next;
}e[];
int f1[],anc[][],log2n,deep[],n,m,s,ne;
bool vis[];
void dfs(int x,int fa)
{
int i,k;
vis[x]=;
anc[x][]=fa;
deep[x]=deep[fa]+;
for(i=;i<=log2n;i++)
anc[x][i]=anc[anc[x][i-]][i-];
for(k=f1[x];k!=;k=e[k].next)
if(!vis[e[k].to])
dfs(e[k].to,x);
}
int lca(int x,int y)
{
int t,i;
if(deep[x]<deep[y]){t=x;x=y;y=t;}
for(t=deep[x]-deep[y],i=;t>;t>>=,i++)
if(t&) x=anc[x][i];
if(x==y) return x;
for(i=log2n;i>=;i--)
if(anc[x][i]!=anc[y][i])
{
x=anc[x][i];
y=anc[y][i];
}
return anc[x][];
}
int main()
{
int i,x,y,a,b;
scanf("%d%d%d",&n,&m,&s);
while((<<(log2n+))<=n) log2n++;
for(i=;i<n;i++)
{
scanf("%d%d",&x,&y);
e[++ne].to=y;
e[ne].next=f1[x];
f1[x]=ne;
e[++ne].to=x;
e[ne].next=f1[y];
f1[y]=ne;
}
dfs(s,);
while(m--)
{
scanf("%d%d",&a,&b);
printf("%d\n",lca(a,b));
}
return ;
}

How far away ? HDU - 2586(求树上两点距离)

方法就是求出dis[i]表示i到根节点的距离,那么两点a,b距离就是$dis[a]+dis[b]-2*dis[lca(a,b)]$

错误笔记:

1.20行写成anc[x][i]=anc[fa][i-1];

2.遗漏18行

 #include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
typedef long long LL;
struct Edge
{
LL to,d,nxt;
}e[];
LL T,n,m,ne;
LL f1[],deep[],anc[][],log2n;
LL dis[];
void dfs(LL x,LL fa)
{
LL i,k;
anc[x][]=fa;
deep[x]=deep[fa]+;
for(i=;i<=log2n;i++)
anc[x][i]=anc[anc[x][i-]][i-];
for(k=f1[x];k!=;k=e[k].nxt)
if(e[k].to!=fa)
{
dis[e[k].to]=dis[x]+e[k].d;
dfs(e[k].to,x);
}
}
LL lca(LL x,LL y)
{
LL t,i;
if(deep[x]<deep[y]) swap(x,y);
for(t=deep[x]-deep[y],i=;t>;t>>=,i++)
if(t&) x=anc[x][i];
if(x==y) return x;
for(i=log2n;i>=;i--)
if(anc[x][i]!=anc[y][i])
{
x=anc[x][i];
y=anc[y][i];
}
return anc[x][];
}
int main()
{
LL i,a,b,w,t;
scanf("%lld",&T);
while(T--)
{
ne=;
memset(f1,,sizeof(f1));
scanf("%lld%lld",&n,&m);
log2n=log2(n);
for(i=;i<n;i++)
{
scanf("%lld%lld%lld",&a,&b,&w);
e[++ne].to=b;
e[ne].nxt=f1[a];
e[ne].d=w;
f1[a]=ne;
e[++ne].to=a;
e[ne].nxt=f1[b];
e[ne].d=w;
f1[b]=ne;
}
dfs(,);
for(i=;i<=m;i++)
{
scanf("%lld%lld",&a,&b);
t=lca(a,b);
printf("%lld\n",dis[a]-dis[t]+dis[b]-dis[t]);
}
}
return ;
}

洛谷 P1967 货车运输(求图中给定两点间的所有路径中,最短边最长的一条路径的最短边)

首先,可以直接取原图的最大生成树,只在这之上查询答案。

原因是,在kruskal生成最大生成树的过程中,是按边权从大到小取边。在判断某条边取不取时,只有两点已经连通,才会不取边,否则一定会取。而如果在判断是否取一条(a,b,w)的边时,a和b已经连通,那么使得a和b连通的路径上任意一条边的权值都一定大于等于w(由于它们都在当前边之前取),也就是使得a和b连通的路径上的最小边权大于等于w。那么对于某两点间路径,如果需要过a到b的路径,那么选择(a,b,w)的路径一定不会比选择使得a和b连通的原来路径更好。

那么,这道题和前面一道就类似了,不过由于最大最小值不满足区间加和,不能简单的像那一道一样用前缀和。正确的方法类似倍增lca求2^i级祖先的过程。

设minn[i][j]表示点i到其2^j级祖先的路径上的最小边权。那么$minn[i][j]=min(minn[i][j-1],minn[anc[i][j-1]][j-1])$。当然,minn[i][0]就是其到父亲的边的边权。这个数组在倍增lca的dfs中可以预处理出来。

在查询的时候,就用倍增lca的查询,但是对于节点向上跳的操作,进行之前应当先把将要跳过的这段路径的最小边权更新到已知的最小边权之上。

错误记录(本地):

1.47、48行打反

2.35行写成anc[e[k].to]=fa

3.缺少87行

4.缺少66行

 #include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
struct E1
{
int a,b,w;
friend bool operator<(const E1& a,const E1& b)
{
return a.w>b.w;
}
}e1[];
struct Edge
{
int to,d,nxt;
}e[];
int fa[],q,n,m,ne,f1[],anc[][],log2n,minn[][],deep[];
int find(int x)
{
return fa[x]==x?x:fa[x]=find(fa[x]);
}
void dfs(int x,int fa)
{
int i,k;
for(i=;i<=log2n;i++)
{
anc[x][i]=anc[anc[x][i-]][i-];
minn[x][i]=min(minn[x][i-],minn[anc[x][i-]][i-]);
}
for(k=f1[x];k!=;k=e[k].nxt)
if(e[k].to!=fa)
{
deep[e[k].to]=deep[x]+;
anc[e[k].to][]=x;
minn[e[k].to][]=e[k].d;
dfs(e[k].to,x);
}
}
int get(int x,int y)
{
int t,ans=0x3f3f3f3f,i;
if(deep[x]<deep[y]) swap(x,y);
for(t=deep[x]-deep[y],i=;t>;t>>=,i++)
if(t&)
{
ans=min(ans,minn[x][i]);
x=anc[x][i];
}
if(x==y) return ans;
for(i=log2n;i>=;i--)
if(anc[x][i]!=anc[y][i])
{
ans=min(ans,minn[x][i]);
ans=min(ans,minn[y][i]);
x=anc[x][i];
y=anc[y][i];
}
return min(ans,min(minn[x][],minn[y][]));
}
int main()
{
int i,t1,t2,a,b;
scanf("%d%d",&n,&m);
log2n=log2(n);
memset(minn,0x3f,sizeof(minn));
for(i=;i<=m;i++)
scanf("%d%d%d",&e1[i].a,&e1[i].b,&e1[i].w);
sort(e1+,e1+m+);
for(i=;i<=n;i++)
fa[i]=i;
for(i=;i<=m;i++)
{
t1=find(e1[i].a);
t2=find(e1[i].b);
if(t1==t2) continue;
e[++ne].to=e1[i].b;
e[ne].nxt=f1[e1[i].a];
e[ne].d=e1[i].w;
f1[e1[i].a]=ne;
e[++ne].to=e1[i].a;
e[ne].nxt=f1[e1[i].b];
e[ne].d=e1[i].w;
f1[e1[i].b]=ne;
fa[t1]=t2;
}
dfs(,);
scanf("%d",&q);
while(q--)
{
scanf("%d%d",&a,&b);
if(a>n||b>n||find(a)!=find(b))
{
printf("-1\n");
continue;
}
printf("%d\n",get(a,b));
}
return ;
}

洛谷P3379lca,HDU2586,洛谷P1967货车运输,倍增lca,树上倍增的更多相关文章

  1. P1967 货车运输[生成树+LCA]

    题目描述 A国有n座城市,编号从 1到n,城市之间有 m 条双向道路.每一条道路对车辆都有重量限制,简称限重.现在有 q* 辆货车在运输货物, 司机们想知道每辆车在不超过车辆限重的情况下,最多能运多重 ...

  2. 【NOIP2013/Codevs3287】货车运输-最小生成树(大)-树上倍增

    https://www.luogu.org/problemnew/show/P1967 由题可知,我们走的路的边应尽可能大,所以通过kruscal建最大生成树的图,再树上倍增,注意可能有多棵树; #i ...

  3. P1967 货车运输【LCA】【生成树】

    题目描述 A 国有 nn 座城市,编号从 11 到 nn,城市之间有 mm 条双向道路.每一条道路对车辆都有重量限制,简称限重. 现在有 qq 辆货车在运输货物, 司机们想知道每辆车在不超过车辆限重的 ...

  4. 洛谷 P1967 货车运输

    洛谷 P1967 货车运输 题目描述 A 国有 n 座城市,编号从 1 到 n,城市之间有 m 条双向道路.每一条道路对车辆都有重量限制,简称限重.现在有 q 辆货车在运输货物, 司机们想知道每辆车在 ...

  5. P1967 货车运输

    P1967 货车运输最大生成树+lca+并查集 #include<iostream> #include<cstdio> #include<queue> #inclu ...

  6. Luogu P1967 货车运输(Kruskal重构树)

    P1967 货车运输 题面 题目描述 \(A\) 国有 \(n\) 座城市,编号从 \(1\) 到 \(n\) ,城市之间有 \(m\) 条双向道路.每一条道路对车辆都有重量限制,简称限重.现在有 \ ...

  7. 「NOIP2013」「LuoguP1967」货车运输(最大生成树 倍增 LCA

    题目描述 AA国有nn座城市,编号从 11到nn,城市之间有 mm 条双向道路.每一条道路对车辆都有重量限制,简称限重.现在有 qq 辆货车在运输货物, 司机们想知道每辆车在不超过车辆限重的情况下,最 ...

  8. 【杂题总汇】NOIP2013(洛谷P1967) 货车运输

    [洛谷P1967] 货车运输 重做NOIP提高组ing... +传送门-洛谷P1967+ ◇ 题目(copy from 洛谷) 题目描述 A国有n座城市,编号从1到n,城市之间有m条双向道路.每一条道 ...

  9. 洛谷P1967货车运输——倍增LCA

    题目:https://www.luogu.org/problemnew/show/P1967 就是倍增LCA的裸题,注意一些细节即可. 代码如下: #include<iostream> # ...

随机推荐

  1. 项目Beta冲刺(团队5/7)

    项目Beta冲刺(团队5/7) 团队名称: 云打印 作业要求: 项目Beta冲刺(团队) 作业目标: 完成项目Beta版本 团队队员 队员学号 队员姓名 个人博客地址 备注 221600412 陈宇 ...

  2. Json的简单介绍和解析

    Json:JavaScript对象表示法(JavaScript Object Noatation) Json是存储和交换文本信息的语法,类似XML.它采用键值对的方式来组织,易于人们阅读和编写,同时也 ...

  3. 基于DM642 RAW采集格式的视频驱动开发及应用

    摘 要:为解决C64X系列数字信号处理器(DSP)视频驱动不能应用于原始数据格式(RAW)采集格式的问题,设计了DM642和电耦合元件(CCD)高清传感器的数据传输接口,并分析.修改用于标准格式的视频 ...

  4. [Selenium]通过Selenium实现在当前浏览器窗口点击一个图标之后,弹出另外一个窗口,关闭这个窗口,再回到原来的窗口进行操作

    public void clickReportIcon(){ String initialWindowHandle = driver.getWindowHandle(); //保存原始的浏览器窗口 p ...

  5. JAVA运行时异常及常见的5中RuntimeExecption

    最近在抽时间看面试题,很多面试题都提出了写出java常见的5个运行时异常.现在来总结一下, java运行时异常是可能在java虚拟机正常工作时抛出的异常. java提供了两种异常机制.一种是运行时异常 ...

  6. hadoop yarn namenode datanoe 启动异常问题解决 分析日志

    cat logs/hadoop-root-datanode-hadoop1.log ********************************************************** ...

  7. ruby 学习网站

    Ruby on Rails官网: http://rubyonrails.org/ Rails Guides:http://guides.rubyonrails.org/ -中文版: http://gu ...

  8. Opencv函数setMouseCallback鼠标事件响应

    用户通过鼠标对图像视窗最常见的操作有: 1. 左键单击按下 2. 左键单击抬起 3. 左键按下拖动 4. 鼠标指针位置移动 单次单击操作响应事件及顺序 Opencv中setMouseCallback( ...

  9. 用mkdirs创建目录

    import java.io.*; class a { public static void main(String args[]) { createDir("c:/fuck"); ...

  10. SPOJ:Another Version of Inversion(二维数组的逆序对)

    DCE Coders admins are way much geekier than they actually seem! Kartik has been following that tradi ...