倍增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. linux进程间通信消息队列:msgsnd: Invalid argument

    今天写了个消息队列的小测试程序结果send端程序总是出现:msgsnd: Invalid argument,搞了半个小时也没搞明白,后来查资料发现我将(st_msg_buf.msg_type = 0; ...

  2. mysql中修改表字段名/字段长度/字段类型详解

    在mysql中我们对数据表字段的修改命令只要使用alter就可以了,下面我来给大家详细介绍mysql中修改表字段名/字段长度/字段类型等等一些方法介绍,有需要了解的朋友可参考. 先来看看常用的方法 M ...

  3. Provided Maven Coordinates must be in the form 'groupId:artifactId:version'.

    [hadoop@hadoop1 bin]$ ./spark-shell --packages org.mongodb.spark:mongo-spark-connector_2.10-2.2.1 Ex ...

  4. C/C++ 操作符优先级

    不能光转贴,有空要熟悉之后,要写点心得.现在发现 . 的优先级确实很高. C: Precedence Operator Description Associativity 1 ++ -- Suffix ...

  5. Hadoop 中的 (side data) 边数据

    一.用途 边数据是作业所需的额外的只读数据,通常用来辅助主数据集: 二.方法 1.利用Configuration类来配置,利用setter()和getter()可方便的使用,方便存储一些基本的类型: ...

  6. 数据库的事务与ACID

    一.事务: 事务(Transaction),一般是指要做的或所做的事情.在计算机术语中是指访问并可能更新数据库中各种数据项的一个程序执行单元(unit).在计算机术语中,事务通常就是指数据库事务. 二 ...

  7. HDU1964 Pipes —— 插头DP

    题目链接:https://vjudge.net/problem/HDU-1964 Pipes Time Limit: 5000/1000 MS (Java/Others)    Memory Limi ...

  8. 老毛桃U盘启动盘,通过ghost创建xp系统蓝屏问题

    新买的东芝笔记本只预安装了dos,找来一个老毛桃U盘启动盘,进入winpe用ghost恢复成xp系统:重启后,系统蓝屏,提示的主要报错代码 0x0000007B 与 要求“chkdsk /f”处理. ...

  9. SpringMVC之使用Validator接口进行验证

    对于任何一个应用而言在客户端做的数据有效性验证都不是安全有效的,这时候就要求我们在开发的时候在服务端也对数据的有效性进行验证.SpringMVC自身对数据在服务端的校验有一个比较好的支持,它能将我们提 ...

  10. 【CQOI2009】中位数图

    [题目链接] 点击打开链接 [算法] 将小于m的数看作-1,大于m的看作1 然后求前缀和,如果区间[l,r]的中位数是m,显然有 : sum(r) - sum(l-1) = 0 因此,只需m的位置之前 ...