倍增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. 获取Bootstrap-Table的所有内容,修改行内容

    var allTableData = $tableLeft.bootstrapTable('getData');//获取表格的所有内容行 var flag = false; for( i=0;i< ...

  2. 流媒体开发之开源项目live555---更改server端的帧率大小和码率大小

    -----------------------------qq:1327706646 010101010101010110010101010101010101010author:midu 010101 ...

  3. ID--HANDLE--HWND三者之间的互相转换

    利用PreTranslateMessage,响应按钮控件的按下(WM_LBUTTONDOWN)和松开(WM_LBUTTONUP)   VC的button控制只有两个事件,一个是单击事件,一个事双击事件 ...

  4. Codeforces Round #422 (Div. 2) B. Crossword solving 枚举

    B. Crossword solving     Erelong Leha was bored by calculating of the greatest common divisor of two ...

  5. 关于yum的一些基本的东西

    1 sqlite数据库的使用 第一,某个centos版本的包相关的信息都放在一个服务器端的sqlite数据库文件中,yum会下载到本地,进行包安装的时候用. 第二,安装的历史记录放在sqlite数据库 ...

  6. luogu2704 炮兵阵地 状态压缩DP

    题目大意:一个N*M的地图由N行M列组成,地图的每一格可能是山地(用“H” 表示),也可能是平原(用“P”表示),在每一格平原地形上最多可以布置一支炮兵部队,能攻击到的区域:沿横向左右各两格,沿纵向上 ...

  7. Hadoop一些要注意的点

    1.大多小文件的劣处: a. 生成更多的map任务,额外的开销: b. 每个文件都需要守址时间: c. HDFS上namenode需要占用内存空间:

  8. (linux)SD卡初始化-mmc_sd_init_card函数

      为了学习SD/SDIO协议,看了一下linux中初始化SD卡的流程,结合代码更容易SD初始化是怎么做的. 下面图截自:"SD Specifications Part 1 Physical ...

  9. HDU3294 Girls' research —— Manacher算法 输出解

    题目链接:https://vjudge.net/problem/HDU-3294 Girls' research Time Limit: 3000/1000 MS (Java/Others)    M ...

  10. 对象数组、集合、链表(java基础知识十五)

    1.对象数组的概述和使用 * 需求:我有5个学生,请把这个5个学生的信息存储到数组中,并遍历数组,获取得到每一个学生信息. Student[] arr = new Student[5]; //存储学生 ...