题目

给出一棵\(n\)个点的树,从1到\(n\)编号,\(m\)次询问\({LCA} _{v\in[L,R]}\)。

\(n,m\le 3\times 10^5​\)

分析

我的做法是直接对LCA进行倍增,即\(f[i][j]\)表示从\(i\)号点开始的\(2^j\)个点的LCA,\(O(n\log ^2 n)\)预处理\(O(\log n)\)查询(分成前后两段,类似RMQ问题中ST表的做法)。

实际上还有复杂度更低的方法。

求一大堆点的共同LCA其实就是求其中dfn序最小和最大的点的LCA。直观的证明如下。取得询问点的中dfn序最小的那个,设为\(x\),另一个点\(v\)点的位置有两种情况:

  • \(v\)在\(x\)的子树内(能满足\(dfn_v>dfn_x\)),那么他们的LCA就是\(x\)
  • \(v\)在\(x\)的子树外,那么它必定在\(x\)的某一个祖先的子树内。这个祖先越往上,\(dfn_v\)就越大。

综上,一堆点的LCA为其中dfn序最小和最大的两点的LCA。

于是这个问题就变成了一个每次得到dfn序的极值点,求一次LCA的了。可以用线段树方便地实现。复杂度为\(O((n+m)\log n)\)。

代码

#include<cstdio>
#include<cctype>
#include<vector>
#include<cstring>
#include<algorithm>
#define M(x) memset(x,0,sizeof x)
using namespace std;
int read() {
int x=0,f=1;
char c=getchar();
for (;!isdigit(c);c=getchar()) if (c=='-') f=-1;
for (;isdigit(c);c=getchar()) x=x*10+c-'0';
return x*f;
}
const int maxn=3e5+1;
const int maxj=19;
int n,st[maxn][maxj],bin[maxn];
namespace tree {
vector<int> g[maxn];
int top[maxn],size[maxn],son[maxn],dep[maxn],fat[maxn];
void clear(int n) {
for (int i=1;i<=n;++i) g[i].clear();
M(top),M(size),M(son),M(dep);
}
void add(int x,int y) {g[x].push_back(y);}
int dfs(int x,int fa) {
int &sz=size[x]=1,&sn=son[x]=0;
dep[x]=dep[fat[x]=fa]+1;
for (int v:g[x]) if (v!=fa) {
sz+=dfs(v,x);
if (size[v]>size[sn]) sn=v;
}
return sz;
}
void Top(int x,int fa,int tp) {
top[x]=tp;
if (son[x]) Top(son[x],x,tp);
for (int v:g[x]) if (v!=fa && v!=son[x]) Top(v,x,v);
}
int lca(int x,int y) {
for (;top[x]!=top[y];dep[top[x]]>dep[top[y]]?x=fat[top[x]]:y=fat[top[y]]);
return dep[x]<dep[y]?x:y;
}
}
int main() {
#ifndef ONLINE_JUDGE
freopen("test.in","r",stdin);
#endif
while (~scanf("%d",&n)) {
tree::clear(n);
for (int i=2;i<=n;++i) bin[i]=bin[i>>1]+1;
M(st);
for (int i=1;i<n;++i) {
int x=read(),y=read();
tree::add(x,y),tree::add(y,x);
}
tree::dfs(1,1);
tree::Top(1,1,1);
for (int i=1;i<=n;++i) st[i][0]=i;
for (int j=1;j<maxj;++j) for (int i=1;i<=n;++i) {
st[i][j]=st[i][j-1];
if ((i+(1<<(j-1)))<=n) st[i][j]=tree::lca(st[i][j],st[i+(1<<(j-1))][j-1]);
}
int m=read();
while (m--) {
int l=read(),r=read();
int len=r-l+1,d=bin[len];
int ans=tree::lca(st[l][d],st[r-(1<<d)+1][d]);
printf("%d\n",ans);
}
}
return 0;
}

HDU5266-pog loves szh III的更多相关文章

  1. hdu5266 pog loves szh III 【LCA】【倍增】

    Pog and Szh are playing games. Firstly Pog draw a tree on the paper. Here we define 1 as the root of ...

  2. hdu 5266 pog loves szh III(lca + 线段树)

    I - pog loves szh III Time Limit:6000MS     Memory Limit:131072KB     64bit IO Format:%I64d & %I ...

  3. HDU 5266 pog loves szh III(区间LCA)

    题目链接 pog loves szh III 题意就是  求一个区间所有点的$LCA$. 我们把$1$到$n$的$DFS$序全部求出来……然后设$i$的$DFS$序为$c[i]$,$pc[i]$为$c ...

  4. HDU 5266 pog loves szh III ( LCA + SegTree||RMQ )

    pog loves szh III Time Limit: 12000/6000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Oth ...

  5. HDU 5266 pog loves szh III 线段树,lca

    Pog and Szh are playing games. Firstly Pog draw a tree on the paper. Here we define 1 as the root of ...

  6. HDU 5266 pog loves szh III (LCA)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5266 题目就是让你求LCA,模版题.注意dfs会栈溢出,所以要扩栈,或者用bfs写. #pragma ...

  7. HDU 5266 pog loves szh III

    题意:给出一棵树,1为根节点,求一段区间内所有点的最近公共祖先. 解法:用一棵线段树维护区间LCA.LCA是dp做法.dp[i][j]表示点i的第2^j个祖先是谁,转移方程为dp[i][j] = dp ...

  8. HDU 5266 pog loves szh III (线段树+在线LCA转RMQ)

    题目地址:HDU 5266 这题用转RMQ求LCA的方法来做的很easy,仅仅须要找到l-r区间内的dfs序最大的和最小的就能够.那么用线段树或者RMQ维护一下区间最值就能够了.然后就是找dfs序最大 ...

  9. hdu 5265 pog loves szh II

    题目连接 http://acm.hdu.edu.cn/showproblem.php?pid=5265 pog loves szh II Description Pog and Szh are pla ...

  10. hdu 5264 pog loves szh I

    题目连接 http://acm.hdu.edu.cn/showproblem.php?pid=5264 pog loves szh I Description Pog has lots of stri ...

随机推荐

  1. PostgreSQL参数学习:max_wal_senders

    磨砺技术珠矶,践行数据之道,追求卓越价值回到上一级页面:PostgreSQL基础知识与基本操作索引页    回到顶级页面:PostgreSQL索引页[作者 高健@博客园  luckyjackgao@g ...

  2. 【洛谷P2016】战略游戏

    题面 题解 树形\(dp\)(最大独立集) 设\(f_{i,0/1}\)表示\(dp\)到第\(i\)个点,在这个点放了(没放)士兵的最小花费 直接转移即可. 代码 #include<cstdi ...

  3. 【BZOJ4560】[NOI2016]优秀的拆分

    [BZOJ4560][NOI2016]优秀的拆分 题面 bzoj 洛谷 题解 考虑一个形如\(AABB\)的串是由两个形如\(AA\)的串拼起来的 那么我们设 \(f[i]\):以位置\(i\)为结尾 ...

  4. SaltStack入门篇(三)之数据系统Grains、Pillar

    1.什么是Grains? Grains是saltstack的组件,用于收集salt-minion在启动时候的信息,又称为静态信息.可以理解为Grains记录着每台Minion的一些常用属性,比如CPU ...

  5. (原创)python发送邮件

    这段时间一直在学习flask框架,看到flask扩展中有一个mail插件,所以今天就给大家演示如果发邮件. 首先我注册了一个163邮箱,需要开启smtp功能,因为咱们python发送邮件经过的是smt ...

  6. 跟浩哥学自动化测试Selenium -- Selenium简介 (1)

    Selenium 简介 Selenium 是一款开源的web自动化测试工具,用来模拟对浏览器的操作(主要是对页面元素的操作),简单来讲,其实就是一个jar包.Selenium早期的版本比如1.0市场占 ...

  7. mybatis 加载配置文件的方法

    一.  使用sqlSessionFactory 的 mapperLocations 进行加载 <!-- SessionFactory --> <bean id="sqlSe ...

  8. 网络流小结(HNOI2019之前)

    \(\text{一:Dinic最大流}\) 最坏复杂度 \({\mathcal O(n^2m)}\) 一般可以处理 \(10^4\) ~ \(10^5\) 的网络. struct Edge { int ...

  9. 简析Monte Carlo与TD算法的相关问题

    Monte Carlo算法是否能够做到一步更新,即在线学习? 答案显然是不能,如果可以的话,TD算法还有何存在的意义?MC算法必须要等到episode结束后才可以进行值估计的主要原因在于对Return ...

  10. 4.openldap创建索引

    1.索引的意义 提高对Openldap目录树的查询速度 提高性能 减轻对服务器的压力 2.搜索索引 ldapsearch -Q -LLL -Y EXTERNAL -H ldapi:/// -b cn= ...