CodeForces-1062E LCA,DFN,RMQ
题目链接
https://vjudge.net/problem/CodeForces-1062E
题意
给出一棵树,编号1-n,每次询问L-R区间点中,删掉一个点后LCA的最小深度(根为0),输出删去的点和深度
思路
训练的时候只想到了最暴力的O(n²qlog(logn))O(n²qlog(logn)) O(n²qlog(logn))的算法。
仔细观察,发现一组点的LCA就是dfn最小和最大的点的LCA,那么如果删点,肯定是删去这两个点其中之一。于是我们用线段树维护区间dfn最大最小值,对于每个询问我们处理出区间内最大dfn,次大dfn,最小dfn,次小dfn对应的节点(需要做dfs时建立映射),比较LCA(最大,次小),LCA(次大,最小)的深度,分情况输出即可。
复杂度
O(q∗(logn+log(logn)))O(q*(logn+log(logn))) O(q∗(logn+log(logn)))
教训/收获
图论部分题很考验直觉/观察。不要自闭,相信自己的实力,毫无头绪和一遍AC很多时候只差一个结论。____一念起,刹那天地宽。
数据结构实在不擅长,调了好久,麻了,线段树这种简单数据结构还是要练一练的
代码
#include<iostream>
#include<string>
#include<queue>
#include<stack>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<cstdlib>
#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define endl "\n"
//#define int long long
using namespace std;typedef long long ll;const int maxn=500005;const int inf=0x3f3f3f3f;int n,m,k,sq_t;int head[maxn],cnt,f[maxn][20],dep[maxn];int dfn[maxn],dfn_to_no[maxn];struct segtree{int l,r;int ma,mi;} t[maxn<<2];void build(int root,int l,int r){t[root].l=l,t[root].r=r;if(l==r){t[root].ma=t[root].mi=dfn[l];return;}ll mid=l+r>>1;build(root<<1,l,mid);build(root<<1|1,mid+1,r);t[root].ma=max(t[root<<1].ma,t[root<<1|1].ma);t[root].mi=min(t[root<<1].mi,t[root<<1|1].mi);}ll qmax(ll root,ll l,ll r){if(l<=t[root].l&&r>=t[root].r){return t[root].ma;}ll mid=t[root].l+t[root].r>>1;ll ans=-1;if (l<=mid) ans=max(qmax(root<<1,l,r),ans);if (r>mid) ans=max(qmax(root<<1|1,l,r),ans);return ans;}ll qmin(ll root,ll l,ll r){if(l<=t[root].l&&r>=t[root].r){return t[root].mi;}ll mid=t[root].l+t[root].r>>1;ll ans=inf;if (l<=mid) ans=min(qmin(root<<1,l,r),ans);if (r>mid) ans=min(qmin(root<<1|1,l,r),ans);return ans;}struct Edge{int to,next;}edge[maxn];void init(){memset(head,-1,sizeof head);cnt=0;}void add(int u,int v){edge[cnt]={v,head[u]};head[u]=cnt++;}queue<int>q;void LCA_prework(int root){q.push(root); dep[root]=1;while(q.size()){int x=q.front();q.pop();for(int i=head[x];~i;i=edge[i].next){int y=edge[i].to;if(dep[y]) continue;dep[y]=dep[x]+1;f[y][0]=x;for(int j=1;j<=sq_t;j++){f[y][j]=f[f[y][j-1]][j-1];}q.push(y);}}}int query_LCA(int x,int y){if(dep[x]>dep[y]) swap(x,y);for(int i=sq_t;i>=0;i--){if(dep[f[y][i]]>=dep[x]){y=f[y][i];}}if(x==y) return x;for(int i=sq_t;i>=0;i--){if(f[x][i]!=f[y][i]) x=f[x][i],y=f[y][i];}return f[x][0];}int dfn_cnt;void dfs(int x){dfn[x]=++dfn_cnt;dfn_to_no[dfn_cnt]=x;for(int i=head[x];~i;i=edge[i].next){if(!dfn[edge[i].to]){dfs(edge[i].to);}}}signed main(){IOS#ifndef ONLINE_JUDGEfreopen("IO\\in.txt","r",stdin);freopen("IO\\out.txt","w",stdout);#endifcin>>n>>m;init();for(int i=2,t;i<=n;i++){cin>>t;add(t,i);add(i,t);}dfs(1);sq_t=(int)(log(n)/log(2))+1;LCA_prework(1);build(1,1,n);while(m--){int x,y;cin>>x>>y;int mmax,mmin,cmax,cmin,mmax_no,mmin_no,cmax_no,cmin_no;mmax=qmax(1,x,y); mmin=qmin(1,x,y);mmax_no=dfn_to_no[mmax];mmin_no=dfn_to_no[mmin];cmax=max(qmax(1,x,mmax_no-1),qmax(1,mmax_no+1,y));cmin=min(qmin(1,x,mmin_no-1),qmin(1,mmin_no+1,y));cmax_no=dfn_to_no[cmax];cmin_no=dfn_to_no[cmin];int ans1=query_LCA(mmax_no,cmin_no);int ans2=query_LCA(mmin_no,cmax_no);if(dep[ans1]>dep[ans2]){cout<<mmin_no<<' '<<dep[ans1]-1<<endl;}else{cout<<mmax_no<<' '<<dep[ans2]-1<<endl;}}}
CodeForces-1062E LCA,DFN,RMQ相关推荐
- 看到的一个很不错的分析LCA和RMQ的文章(转载,先收着)
首先请看定义: 一.最近公共祖先(Least Common Ancestors) 对于有根树T的两个结点u.v,最近公共祖先LCA(T,u,v)表示一个结点x,满足x是u.v的祖先且x的深度尽可能大. ...
- 洛谷 - P3379 【模板】最近公共祖先(LCA)(RMQ求LCA/Tarjan求LCA)
题目链接:点击查看 题目大意:给出一棵 n 个点组成的有根树,再给出 m 次询问,每次询问需要回答点 x 和点 y 的 lca 题目分析:今天新学了两种蛮有意思的求 LCA 的方法,总结一下四种方法各 ...
- LCA(包含RMQ)
今天看了RMQ问题 ST的实质是动归 于是我来回顾一下LCA(的各种写法) 因为每次考试发现自己连LCA都写不好 费时 First of all, RMQ板子: [一维] #include<bi ...
- The Shortest Statement CodeForces - 1051F LCA+最短路
太弱了... 一开始看到题感觉是跑一个最小生成树在上边进行LCA就行了,但是发现过不了样例,然后就是就想到了之前做过类似做法的题目,就是非生成树上的边最多只有21条,然后就那些边记录下来,通过每一条边 ...
- A and B and Lecture Rooms CodeForces - 519E LCA+dfs序
看到这个题的第一个思路就是就是统计以每一个点为根的所有节点个数,然后具体就分情况讨论一下即可. 因为刚刚学习了dfs序,这个题就用了dfs序来通过进出时间戳来相减表示其为根的子节点个数. 分情况 我们 ...
- HDU 4338 Simple Path 点双连通+lca
[题目大意] 给你一个无向图.问,从点u到点v,若是只走简单路径,有多少个点不能到达? [思路] 这题肯定是要双连通缩点的,以前老是觉得点双连通不会用来缩点,因为割点可以属于多个连通集合,现在立马打脸 ...
- 图论--最近公共祖先LCA
最近公共祖先LCA LCA(Least Common Ancestors),即最近公共祖先,是指这样一个问题:在有根树中,找出某两个结点u和v最近的公共祖先(另一种说法,离树根最远的公共祖先) 最近公 ...
- poj1330Nearest Common Ancestors(LCA小结)
题目请戳这里 题目大意:意如其名. 题目分析:本题只有一个查询,所以可以各种乱搞过去. 不过对于菜鸟而言,还是老老实实练习一下LCA算法. LCA有很多经典的算法.按工作方式分在线和离线2种. tar ...
- BZOJ 4326 NOIP2015 运输计划(树上差分+LCA+二分答案)
4326: NOIP2015 运输计划 Time Limit: 30 Sec Memory Limit: 128 MB Submit: 1388 Solved: 860 [Submit][Stat ...
最新文章
- 三种基本排序的实现及其效率对比:冒泡排序、选择排序和插入排序
- windows 2003系统目前最完善最完美的安全权限方案(转)
- 页面是可以这样设计的
- ML之FE:基于LiR/Ridge/Lasso/ElasticNet/AvgModels/RF算法(GSCV) 利用某市房价数据集(特征工程处理)进行房价回归预测
- mysql 只读账号_MySql主从复制,从原理到实践!
- queryList爬虫获取内容的几种方法总结 queryList给抓取的内容增加html追加元素html 代码实例...
- 随想录(python第三方库中的 setup.py)
- 【吴恩达机器学习】正则化
- SQL语法提示工具SQL Prompt 发布v10.6
- Win10下如何清理优化C盘
- android MTK手机adb remount 失败,如何remont成功?
- Minecraft mod制作简易教程(二)——Mod配置
- 正点原子IIC例程讲解笔记(三)——24cxx.c中函数理解
- 彻底理解js的作用域链
- 编写一个程序,输入直角三角形的两个直角边的长度a、b,求斜边c的长度。
- 分布式算法(中科大分布式算法课程笔记)
- 找回淘宝的“高级搜索”功能
- linux内核添加系统调用(详细)
- 国产EDA工具Robei与Quartus ii联合使用(及在Rrobei设计中一些小技巧)
- (zzulioj1007)鸡和兔关在一个笼子里,鸡有2只脚,兔有4只脚,没有例外。已知现在可以看到笼子里m个头和n只脚,求鸡和兔子各有多少只