板子

ll lg[40];

ll dep[N],fa[N][40];
ll dis[N];
void dfs(ll u,ll f)
{
dep[u]=dep[f]+1;
fa[u][0]=f;
for(int i=1;i<=lg[dep[u]];i++)
{
fa[u][i]=fa[fa[u][i-1]][i-1];
}
for(int i=head[u];i;i=next[i])
{
ll v=e[i].v;
if(v==f)continue;
dis[v]=dis[u]+e[i].w;
dfs(v,u);
}
} ll lca(ll a,ll b)
{
if(dep[a]<dep[b])swap(a,b);
while(dep[a]>dep[b])
{
a=fa[a][lg[dep[a]-dep[b]]];
}
if(a==b)return a;
for(int i=lg[dep[a]];i>=0;i--)
{
if(fa[a][i]!=fa[b][i])
{
a=fa[a][i];
b=fa[b][i];
}
}
return fa[a][0];
}
void lgp()
{
for(int i=2;i<=n;i++)
{
lg[i]=lg[i-1]+((2<<lg[i-1])==i);
}
}

牧场旅行

记一个比较容易的结论:

树上路径长:

\[dis(u,v)=dis(1,u)+dis(1,v)-2\cdot dis[1,lca(u,v)]
\]

这道题就是用这个结论套\(lca\)板子

然后注意写不要在\(if\)语句的同行加分号……(就是直接判了个寂寞)

Distance Queries 距离咨询

怕不是和牧场旅行完全重题……

记下是因为要注意预处理\(lg\)数组的时候是从\(1\)开始的

然后输入的方向根本没用……

货车运输&&星际导航

这两题就只是最大最小相反好吧……

之前学树剖的时候做过货车这道题,树剖方法见这篇博客

这里记一下倍增方法

首先容易想到这条符合题意的路径肯定是在无向图的最大/最小生成树上的,于是先用\(kruskal\)把这棵树抠出来,然后树上倍增求即可

相当于一个树上的\(RMQ\),所以用倍增解决,跟求\(lca\)时差不了太多,就是多维护了一个区间最值数组,然后跳的时候顺便记得用它更新答案

再就是\(kruskal\)之前先把边存在别的地方,要不会出玄学错误……

代码(以货车运输为例)

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define ull unsigned long long
#define ZZ_zuozhe int main()
#define N 50005
#define E 500005 ll n,m,a,b,c,q; struct edge
{
ll u,v,w;
}e[E],t[E];
ll tot=0,head[E],next[E];
void add(ll a,ll b,ll c)
{
++tot;
e[tot].u=a;
e[tot].v=b;
e[tot].w=c;
next[tot]=head[a];
head[a]=tot;
}
bool cmp(edge a,edge b)
{
return a.w>b.w;
} ll lg[E];
void lgp()
{
for(int i=2;i<=m;i++)lg[i]=lg[i>>1]+1;
} ll dep[N],fa[N][30],mx[N][30]; void dfs(ll u,ll f)
{
dep[u]=dep[f]+1;
fa[u][0]=f;
for(int i=1;i<=lg[dep[u]];i++)
{
fa[u][i]=fa[fa[u][i-1]][i-1];
}
for(int i=head[u];i;i=next[i])
{
ll v=e[i].v;
if(v==f)continue;
mx[v][0]=e[i].w;
dfs(v,u);
}
} void mxp()
{
for(int j=1;j<=lg[n];j++)
{
for(int i=1;i<=n;i++)
{
mx[i][j]=min(mx[i][j-1],mx[fa[i][j-1]][j-1]);
}
}
} ll f[N];
ll fd(ll a)
{
if(f[a]==a)return a;
else return f[a]=fd(f[a]);
}
void uni(ll a,ll b)
{
ll x=fd(a),y=fd(b);
f[y]=x;
} void kruskal()
{
sort(t+1,t+m+1,cmp);
memset(head,0,sizeof head);
tot=0;
for(int i=1;i<=n;i++)f[i]=i;
for(int i=1;i<=m;i++)
{
ll a=t[i].u,b=t[i].v,c=t[i].w;
if(fd(a)!=fd(b))
{
uni(a,b);
add(a,b,c);
add(b,a,c);
}
}
} ll lca(ll a,ll b)
{
ll res=1000000000000000000;
if(dep[a]<dep[b])swap(a,b);
while(dep[a]>dep[b])
{
res=min(res,mx[a][lg[dep[a]-dep[b]]]);
a=fa[a][lg[dep[a]-dep[b]]];
}
if(a==b)return res;
for(int i=lg[dep[a]];i>=0;i--)
{
if(fa[a][i]!=fa[b][i])
{
res=min(res,mx[a][i]);
res=min(res,mx[b][i]);
a=fa[a][i];
b=fa[b][i];
}
}
res=min(res,mx[a][0]);
res=min(res,mx[b][0]);
return res;
} ZZ_zuozhe
{
//freopen("owo.in","r",stdin);
//freopen("awa.out","w",stdout);
scanf("%lld%lld",&n,&m);
lgp();
for(int i=1;i<=m;i++)
{
scanf("%lld%lld%lld",&t[i].u,&t[i].v,&t[i].w);
}
kruskal();
dep[0]=0;
for(int i=1;i<=n;i++)if(!dep[i])dfs(i,0);
mxp();
scanf("%lld",&q);
for(int i=1;i<=q;i++)
{
scanf("%lld%lld",&a,&b);
if(fd(a)!=fd(b))puts("-1");
else printf("%lld\n",lca(a,b));
}
return 0;
}

bzoj3306 树

就是遥远的国度嘛\(qaq\)

这篇博客里有思路和树剖的版本,这里给出倍增方法的

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define ull unsigned long long
#define ZZ_zuozhe int main()
#define N 200005 ll n,q,a,b,root,rt;
char ch[3]; struct edge
{
ll u,v;
}e[N];
ll tot=0,head[N],next[N];
void add(ll a,ll b)
{
++tot;
e[tot].u=a;
e[tot].v=b;
next[tot]=head[a];
head[a]=tot;
} ll lg[N];
void lgp()
{
for(int i=2;i<=n;i++)lg[i]=lg[i>>1]+1;
} ll dep[N],fa[N][30];
ll l[N],r[N],cnt=0;
ll num[N],w[N]; void dfs(ll u,ll f)
{
l[u]=++cnt;
num[l[u]]=w[u];
fa[u][0]=f;
dep[u]=dep[f]+1;
for(int i=1;i<=lg[dep[u]];i++)
{
fa[u][i]=fa[fa[u][i-1]][i-1];
}
for(int i=head[u];i;i=next[i])
{
ll v=e[i].v;
if(v==f)continue;
dfs(v,u);
}
r[u]=cnt;
} ll lca(ll a,ll b)
{
if(dep[a]<dep[b])swap(a,b);
while(dep[a]>dep[b])
{
a=fa[a][lg[dep[a]-dep[b]]];
}
if(a==b)return a;
for(int i=lg[dep[a]];i>=0;i--)
{
if(fa[a][i]!=fa[b][i])
{
a=fa[a][i];
b=fa[b][i];
}
}
return fa[a][0];
} #define lson rt<<1,l,m
#define rson rt<<1|1,m+1,r
ll tree[N<<2]; void upd(ll rt)
{
tree[rt]=min(tree[rt<<1],tree[rt<<1|1]);
} void build(ll rt,ll l,ll r)
{
if(l==r)
{
tree[rt]=num[l];//cout<<l<<' '<<tree[rt]<<endl;
return;
}
ll m=(l+r)>>1;
build(lson);
build(rson);
upd(rt);
} void change(ll rt,ll l,ll r,ll n,ll val)
{
if(l==r)
{
tree[rt]=val;
return;
}
ll m=(l+r)>>1;
if(m>=n)change(lson,n,val);
if(m<n)change(rson,n,val);
upd(rt);
} ll query(ll rt,ll l,ll r,ll nl,ll nr)
{
if(nl<=l&&r<=nr)
{
//cout<<' '<<tree[rt]<<endl;
return tree[rt];
}
ll m=(l+r)>>1;
ll ans=1000000000000000000;
if(m>=nl)ans=min(ans,query(lson,nl,nr));
if(m<nr)ans=min(ans,query(rson,nl,nr));
return ans;
} ZZ_zuozhe
{
//freopen("owo.in","r",stdin);
scanf("%lld%lld",&n,&q);
lgp();
for(int i=1;i<=n;i++)
{
scanf("%lld%lld",&a,&w[i]);
if(a)add(a,i);
if(a==0)root=i;
}
dfs(root,0);
rt=root;
build(1,1,n);
for(int i=1;i<=q;i++)
{
scanf("%s",ch);
if(ch[0]=='V')
{
scanf("%lld%lld",&a,&b);
//cout<<'\t'<<l[a]<<' '<<b<<endl;
change(1,1,n,l[a],b);
}
else if(ch[0]=='E')
{
scanf("%lld",&rt);
}
else if(ch[0]=='Q')
{
scanf("%lld",&a);
//cout<<' '<<a<<' '<<rt<<endl;
if(a==rt)printf("%lld\n",tree[1]);
else if(l[a]>l[rt]||r[a]<l[rt])printf("%lld\n",query(1,1,n,l[a],r[a]));
else
{
ll now=rt;
for(int i=16;i>=0;i--)
{
if(dep[fa[now][i]]>dep[a])now=fa[now][i];
}
printf("%lld\n",min(query(1,1,n,1,l[now]-1),query(1,1,n,r[now]+1,n)));
}
}
}
}

「刷题笔记」LCA问题相关的更多相关文章

  1. 「刷题笔记」AC自动机

    自动AC机 Keywords Research 板子题,同luoguP3808,不过是多测. 然后多测不清空,\(MLE\)两行泪. 板子放一下 #include<bits/stdc++.h&g ...

  2. 「刷题笔记」DP优化-状压-EX

    棋盘 需要注意的几点: 题面编号都是从0开始的,所以第1行实际指的是中间那行 对\(2^{32}\)取模,其实就是\(unsigned\ int\),直接自然溢出啥事没有 棋子攻击范围不会旋转 首先, ...

  3. 「刷题笔记」Tarjan

    贴一个讲得非常详细的\(tarjan\)入门教程 信息传递 讲个笑话:我之前用并查集求最小环过的这题,然后看见题目上有个\(tarjan\)标签 留下了深刻的印象:\(tarjan\)就是并查集求最小 ...

  4. 「刷题笔记」哈希,kmp,trie

    Bovine Genomics 暴力 str hash+dp 设\(dp[i][j]\)为前\(i\)组匹配到第\(j\)位的方案数,则转移方程 \[dp[i][j+l]+=dp[i-1][j] \] ...

  5. 《Data Structures and Algorithm Analysis in C》学习与刷题笔记

    <Data Structures and Algorithm Analysis in C>学习与刷题笔记 为什么要学习DSAAC? 某个月黑风高的夜晚,下班的我走在黯淡无光.冷清无人的冲之 ...

  6. Python 刷题笔记

    Python 刷题笔记 本文记录了我在使用python刷题的时候遇到的知识点. 目录 Python 刷题笔记 选择.填空题 基本输入输出 sys.stdin 与input 运行脚本时传入参数 Pyth ...

  7. ☕【JVM技术指南】「JVM总结笔记」Java虚拟机垃圾回收认知和调优的"思南(司南)"【下部】

    承接上文 (完结撒花1-52系列)[JVM技术指南]「JVM总结笔记」Java虚拟机垃圾回收认知和调优的"思南(司南)"[上部] 并行收集器 并行收集器(也称为吞吐量收集器)是类似 ...

  8. PTA刷题笔记

    PTA刷题记录 仓库地址: https://github.com/Haorical/Code/tree/master/PTA/GPLT 两周之内刷完GPLT L2和L3的题,持续更新,包括AK代码,坑 ...

  9. 看完互联网大佬的「LeetCode 刷题手册」, 手撕了 400 道 Leetcode 算法题

    大家好,我是 程序员小熊 ,来自 大厂 的程序猿.相信绝大部分程序猿都有一个进大厂的梦想,但相较于以前,目前大厂的面试,只要是研发相关岗位,算法题基本少不了,所以现在很多人都会去刷 Leetcode ...

随机推荐

  1. Java学习的第四十七天

    1.用类函数来写时间类 import java.util.Scanner; public class Cjava { public static void main(String[]args) { T ...

  2. Linux 网络编程的5种IO模型:多路复用(select/poll/epoll)

    Linux 网络编程的5种IO模型:多路复用(select/poll/epoll) 背景 我们在上一讲 Linux 网络编程的5种IO模型:阻塞IO与非阻塞IO中,对于其中的 阻塞/非阻塞IO 进行了 ...

  3. NOIP 2018 D1 解题报告(Day_1)

    总分   205分 T1 100分 T2  95分 T3  10分 T1: 题目描述 春春是一名道路工程师,负责铺设一条长度为 nn 的道路. 铺设道路的主要工作是填平下陷的地表.整段道路可以看作是  ...

  4. c# 表达式树(一)

    前言 打算整理c# 代码简化史系列,所以相关的整理一下,简单的引出一下概念. 什么是表达式树呢? 表达式树以树形数据结构表示代码,其中每一个节点都是一种表达式,比如方法调用和 x < y 这样的 ...

  5. unicode与编码的关系

    参考链接先贴上来:https://blog.csdn.net/humadivinity/article/details/79403625https://www.cnblogs.com/kevin2ch ...

  6. How to refresh datasource args caller[X++]

    To refresh  datasource args caller, you must add override method close on form like source code belo ...

  7. php 使用 phpword 操作 word 读取 word

    思路 1. 加载word文件.2. 循环判断加载出来的数据.( 数据下面有很多个节点 )( 节点是按照数据的类型分类的 例如 无样式的文本是RunText,换行是TextBreak,表格是table. ...

  8. python super继承用法

    子类对父类的继承一般写法为1, 高级方法为super. 1 # 1,普通继承 2 #新建一个父类 3 class Father(): 4 def father(self,message): 5 pri ...

  9. OLTP与OLAP分析与比较

    (本文转载自Super_Mu的博客https://www.cnblogs.com/hhandbibi/p/7118740.html) 1.OLTP与OLAP的介绍 数据处理大致可以分成两大类:联机事务 ...

  10. Bad magic number ImportError in python

    是源码编译里面版本不对,删除掉源码pyc然后重新编译就可以了 find .-name '*.pyc'-delete python -m compileall . 更新历史 why when 创建 20 ...