BZOJ5165: 树上倍增
Posted mt-li
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了BZOJ5165: 树上倍增相关的知识,希望对你有一定的参考价值。
Description
现有一棵树。您需要写一个树上倍增算法,以实现如下操作:
A x 新建一个节点,将它作为x节点的儿子,编号为当前节点总数+1。
Q k p1 p2 p3.... 查询p1,p2,p3...这些节点的LCA。其中k表示查询节点的个数。
最初树上只有一个节点,编号为1。
多个节点的LCA定义为:这些节点的公共祖先中深度最大的。
Input
第一行,一个正整数,表示操作个数。
接下来行,每行输入一个操作,格式如题目描述所述。
保证任何输入的数都是正整数。
n≤3000000 k≤1000。
保证询问不超过1000次
Output
对于每一个Q操作,输出一行一个正整数,表示所询问节点的LCA。
Sample Input
10
A 1
A 2
A 3
A 1
A 5
A 5
Q 2 3 6
Q 2 6 7
Q 2 4 2
Q 3 7 6 5
A 1
A 2
A 3
A 1
A 5
A 5
Q 2 3 6
Q 2 6 7
Q 2 4 2
Q 3 7 6 5
Sample Output
1
5
2
5
解释
3,6的LCA是1。
6,7的LCA是5。
4,2的LCA是2。
7,6,5的LCA是5。
5
2
5
解释
3,6的LCA是1。
6,7的LCA是5。
4,2的LCA是2。
7,6,5的LCA是5。
疯了这道题还卡我空间。。f**k,出题人%^#&$#^#!#@$^&#*
他说LCA就LCA啊,没什么改变。。
多点LCA??我不会。。
Rose说就是一个贪心,你一直往上跳,看看行不行即可
至于时间。。25s的题也就那样。。。
代码如下:
#include<cmath> #include<cstdio> #include<cstring> #include<cstdlib> #include<algorithm> using namespace std; int bin[25],fa[3000010][21],dep[3000100]; int n,Q,m; char st[51]; int a[3100]; bool cmp(int x,int y){return dep[x]>dep[y];} bool check(int j) { for(int i=1;i<m;i++)if(fa[a[i]][j]!=fa[a[i+1]][j])return true; return false; } int main() { scanf("%d",&Q); bin[0]=1;for(int i=1;i<=24;i++)bin[i]=bin[i-1]<<1; dep[1]=1;fa[1][0]=0;n=1; while(Q--) { scanf("%s%d",st+1,&m); if(st[1]==‘A‘) { n++;int f=m; dep[n]=dep[f]+1;fa[n][0]=f; for(int i=1;bin[i]<=dep[n];i++)fa[n][i]=fa[fa[n][i-1]][i-1]; } else { for(int i=1;i<=m;i++)scanf("%d",&a[i]); sort(a+1,a+1+m,cmp); for(int i=20;i>=0;i--) for(int j=1;j<m;j++) if(bin[i]<=dep[a[j]]&&dep[fa[a[j]][i]]>=dep[a[m]])a[j]=fa[a[j]][i]; bool bk=true; for(int i=2;i<=m;i++)if(a[i]!=a[i-1]){bk=false;break;} if(bk==true){printf("%d\n",a[1]);continue;} for(int i=20;i>=0;i--) if(bin[i]<=dep[a[1]]&&check(i)==true) for(int j=1;j<=m;j++) a[j]=fa[a[j]][i]; printf("%d\n",fa[a[1]][0]); } } return 0; }
by_lmy
以上是关于BZOJ5165: 树上倍增的主要内容,如果未能解决你的问题,请参考以下文章
BZOJ 3551[ONTAK2010] Peaks加强版 Kruskal重构树+树上倍增+主席树
BZOJ-4281Zwi?zek Harcerstwa Bajtockiego 树上倍增LCA
bzoj 3569 DZY Loves Chinese II 随机算法 树上倍增