LCA(包含RMQ)
今天看了RMQ问题
ST的实质是动归
于是我来回顾一下LCA(的各种写法)
因为每次考试发现自己连LCA都写不好
费时
First of all, RMQ板子:
[一维]
#include<bits/stdc++.h>
using namespace std;
const int N = 50010;
int n, q, a, b;
int c[N];
int dpmn[N][20], dpmx[N][20];
template <typename T>
T read(){
T N(0), F(1);
char C = getchar();
for(; !isdigit(C); C = getchar()) if(C == '-') F = -1;
for(; isdigit(C); C = getchar()) N = N*10 + C-48;
return N*F;
}
void rmqmx(){
for(int i = 1; i <= n; i++) dpmx[i][0] = c[i];
for(int j = 1; (1<<j) <= n; j++)
for(int i = 1; i+(1<<j)-1<=n; i++)
dpmx[i][j] = max(dpmx[i][j-1], dpmx[i+(1<<(j-1))][j-1]);
}
void rmqmn(){
for(int i = 1; i <= n; i++) dpmn[i][0] = c[i];
for(int j = 1; (1<<j) <= n; j++)
for(int i = 1; i+(1<<j)-1 <= n; i++)
dpmn[i][j] = min(dpmn[i][j-1], dpmn[i+(1<<(j-1))][j-1]);
}
int rmx(int l, int r){
int k = (int)(log(r-l+1.0)/log(2.0));
return max(dpmx[l][k], dpmx[r-(1<<k)+1][k]);
}
int rmn(int l, int r){
int k = (int)(log(r-l+1.0)/log(2.0));
return min(dpmn[l][k], dpmn[r-(1<<k)+1][k]);
}
int main(){
freopen("rmq.in", "r", stdin);
freopen("rmq.out","w",stdout);
n = read<int>(); q = read<int>();
for(int i = 1; i <= n; i++) c[i] = read<int>();
rmqmx();
rmqmn();
for(int i = 1; i <= q; i++){
a = read<int>(); b = read<int>();
printf("%d\n", rmx(a, b) - rmn(a, b));
}
return 0;
}
[二维-n*m(可能超空间)]
#include<bits/stdc++.h>
using namespace std;
const int N = 260;
template <typename T>
T read(){
T n(0), f(1);
char ch = getchar();
for(; !isdigit(ch); ch = getchar()) if(ch == '-') f = -1;
for(; isdigit(ch); ch = getchar()) n = n*10 + ch-48;
return n*f;
}
int n, k, b;
int a[N][N];
int rmx[N][N][8][8], rmn[N][N][8][8];
void init(){
for(int i = 1; i <= n; i++)
for(int j = 1; j <= n; j++) rmx[i][j][0][0] = rmn[i][j][0][0] = a[i][j];
for(int p = 0; (1<<p) <= n; p++){
for(int q = 0; (1<<q) <= n; q++){
if(p+q){
for(int i = 1; i+(1<<p)-1 <= n; i++){
for(int j = 1; j+(1<<q)-1 <= n; j++){
if(p){
rmx[i][j][p][q] = max(rmx[i][j][p-1][q], rmx[i+(1<<(p-1))][j][p-1][q]);
rmn[i][j][p][q] = min(rmn[i][j][p-1][q], rmx[i+(1<<(p-1))][j][p-1][q]);
}
else{
rmx[i][j][p][q] = max(rmx[i][j][p][q-1], rmx[i][j+(1<<(q-1))][p][q-1]);
rmn[i][j][p][q] = min(rmn[i][j][p][q-1], rmn[i][j+(1<<(q-1))][p][q-1]);
}
}
}
}
}
}
}
int rmqmax(int x1, int y1, int x2, int y2){
int k1 = 0;
while(1<<(k1+1) <= x2-x1+1) k1++;
int k2 = 0;
while(1<<(k2+1) <= y2-y1+1) k2++;
x2 = x2 - (1<<k1) + 1;
y2 = y2 - (1<<k2) + 1;
return max(max(rmx[x1][y1][k1][k2], rmx[x1][y2][k1][k2]), max(rmx[x2][y1][k1][k2], rmx[x2][y2][k1][k2]));
}
int rmqmin(int x1, int y1, int x2, int y2){
int k1 = 0;
while(1<<(k1+1) <= x2-x1+1) k1++;
int k2 = 0;
while(1<<(k2+1) <= y2-y1+1) k2++;
x2 = x2 - (1<<k1) + 1;
y2 = y2 - (1<<k2) + 1;
return min(min(rmn[x1][y1][k1][k2], rmn[x1][y2][k1][k2]), min(rmn[x2][y1][k1][k2], rmn[x2][y2][k1][k2]));
}
int main(){
freopen("p2019.in", "r", stdin);
freopen("p2019.out","w",stdout);
n = read<int>(); b = read<int>(); k = read<int>();
for(int i = 1; i <= n; i++){
for(int j = 1; j <= n; j++){
a[i][j] = read<int>();
}
}
init();
int x, y;
while(k--){
x = read<int>(); y = read<int>();
int ans = rmqmax(x, y, x+b-1, y+b-1) - rmqmin(x, y, x+b-1, y+b-1);
printf("%d\n", ans);
}
return 0;
}
[二维-n*n(空间上好一点点?)]
#include<stdio.h>
#include<string.h>
#include<iostream>
#include<math.h>
using namespace std;
int maxn[255][255][15];
int minn[255][255][15];
int n,b,q;
void ST()
{
int len=floor(log10(double(n))/log10(double(2)));
for(int k=1;k<=n;k++)
{
for(int j=1;j<=len;j++)
{
for(int i=1;i<=(n+1)-(1<<j);i++)
{
maxn[k][i][j]=max(maxn[k][i][j-1],maxn[k][i+(1<<(j-1))][j-1]);
minn[k][i][j]=min(minn[k][i][j-1],minn[k][i+(1<<(j-1))][j-1]);
}
}
}
}
int main()
{
while(~scanf("%d%d%d",&n,&b,&q))
{
memset(maxn,0,sizeof(maxn));
memset(minn,0,sizeof(minn));
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
int tmp;
scanf("%d",&tmp);
maxn[i][j][0]=tmp;
minn[i][j][0]=tmp;
}
}
ST();
while(q--)
{
int x,y;
int ma=-0x3f3f3f3f;
int mi=0x3f3f3f3f;
scanf("%d%d",&x,&y);
int len=floor(log10(double(b))/log10(double(2)));
for(int i=x;i<x+b;i++)
{
ma=max(max(maxn[i][y][len],maxn[i][(y+b-1)-(1<<len)+1][len]),ma);
mi=min(min(minn[i][y][len],minn[i][(y+b-1)-(1<<len)+1][len]),mi);
}
//printf("%d %d\n",ma,mi);
printf("%d\n",ma-mi);
}
}
}
在线:DFS+ST(思想是:将树看成一个无向图,u和v的公共祖先一定在u与v之间的最短路径上)
在线:DFS+倍增
跳到同一层,然后一起跳。
poj1330
题意:求一对点的LCA,无边权。
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<vector>
using namespace std;
const int N = 10010;
template <typename T>
T read(){
T n(0), f(1);
char ch = getchar();
for(; !isdigit(ch); ch = getchar()) if(ch == '-') f = -1;
for(; isdigit(ch); ch = getchar()) n = n*10 + ch-48;
return n*f;
}
int t, n, e, qx, qy, rt;
int f[N][30];
int to[N<<1], nxt[N<<1];
int dep[N], Begin[N], flag[N];
void init(){
e = 0;
memset(to, 0, sizeof(to));
memset(nxt, 0, sizeof(nxt));
memset(Begin, 0, sizeof(Begin));
for(int i = 1; i <= n; ++i){
dep[i] = flag[i] = 0;
}
}
void add(int x, int y){
to[++e] = y; nxt[e] = Begin[x]; Begin[x] = e;
}
void dfs(int u, int f = 0){
for(int i = Begin[u]; i; i = nxt[i]){
int v = to[i];
if(v == f) continue;
dep[v] = dep[u]+1;
dfs(v, u);
}
}
int lca(int u, int v){
if(dep[u] < dep[v]) swap(u, v);
int dis = dep[u]-dep[v];
for(int i = 0; i <= 29; ++i){
if((dis & (1<<i))) u = f[u][i];
}
if(u == v) return u;
for(int i = 29; i >= 0; --i){
if(f[u][i] != f[v][i] && f[u][i]){
u = f[u][i]; v = f[v][i];
}
}
return f[u][0];
}
int main(){
t = read<int>();
while(t--){
n = read<int>();
init();
for(int i = 1; i < n; ++i){
int x, y;
x = read<int>();
y = read<int>();
add(x, y);
f[y][0] = x;
flag[y]++;
}
for(int j = 1; j <= 29; ++j)
for(int i = 1; i <= n; ++i)
f[i][j] = f[f[i][j-1]][j-1];
for(int i = 1; i <= n; ++i) if(!flag[i]) dfs(i);
qx = read<int>(); qy = read<int>();
printf("%d\n", lca(qx, qy));
}
return 0;
}
离线:Tarjan
Here
poj1330
题意:求一对点的LCA,无边权。
P.S.顺便知道如何处理可能为森林的情况。
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<vector>
using namespace std;
const int N = 10010;
template <typename T>
T read(){
T n(0), f(1);
char ch = getchar();
for(; !isdigit(ch); ch = getchar()) if(ch == '-') f = -1;
for(; isdigit(ch); ch = getchar()) n = n*10 + ch-48;
return n*f;
}
int t, n, e, qx, qy, ans;
int to[N<<1], nxt[N<<1];
int begin[N], vis[N], deg[N], fa[N];
vector<int> p[N];
void init(){
ans = e = 0;
memset(vis, 0, sizeof(vis));
memset(deg, 0, sizeof(deg));
memset(to, 0, sizeof(to));
memset(nxt, 0, sizeof(nxt));
memset(begin, 0, sizeof(begin));
for(int i = 1; i <= n; ++i){
fa[i] = i;
p[i].clear();
}
}
void add(int x, int y){
to[++e] = y; nxt[e] = begin[x]; begin[x] = e;
}
int find(int x){
return x == fa[x] ? x : fa[x] = find(fa[x]);
}
void tarjan(int u, int f = 0){
for(int i = begin[u]; i; i = nxt[i]){
int v = to[i];
if(v == f) continue;
tarjan(v, u);
fa[v] = u;
}
vis[u] = 1;
for(int i = 0; i < p[u].size(); ++i){
int v = p[u][i];
if(vis[v]){
ans = find(v);
return;
}
}
}
int main(){
t = read<int>();
while(t--){
n = read<int>();
init();
for(int i = 1; i < n; ++i){
int x, y;
x = read<int>();
y = read<int>();
add(x, y);
deg[y]++;
}
qx = read<int>(); qy = read<int>();
p[qx].push_back(qy);
p[qy].push_back(qx);
for(int i = 1; i <= n; ++i)
if(!deg[i]) tarjan(i);
printf("%d\n", ans);
}
return 0;
}
codevs2370
题意:给定有边权的树,m组询问给出点对,求点对之间的最短路。
P.S.
1、记dep[i]为i到根节点的距离,x、y间的最短路为dep[x]+dep[y]-2*dep[lca(x, y)].
2、离线会导致得到答案的顺序与询问顺序不同,用链式前向星记录,即可按顺序输出。
#include<bits/stdc++.h>
using namespace std;
const int N = 50010;
const int M = 75010;
template <typename T>
T read(){
T n(0), f(1);
char ch = getchar();
for(; !isdigit(ch); ch = getchar()) if(ch == '-') f = -1;
for(; isdigit(ch); ch = getchar()) n = n*10 + ch-48;
return n*f;
}
int n, m, e, e_;
int to[N<<1], nxt[N<<1], w[N<<1];
int to_[M<<1], nxt_[M<<1], w_[M<<1];
int begin[N], fa[N], begin_[M], dep[N], vis[N];
void init(){
for(int i = 1; i <= n; ++i) fa[i] = i;
}
void add(int x, int y, int z){
to[++e] = y; nxt[e] = begin[x]; w[e] = z; begin[x] = e;
}
void add_(int x, int y){
to_[++e_] = y; nxt_[e_] = begin_[x]; begin_[x] = e_;
}
int find(int x){
return x == fa[x] ? x : fa[x] = find(fa[x]);
}
void dfs(int u, int f = 0){
for(int i = begin[u]; i; i = nxt[i]){
int v = to[i];
if(v == f) continue;
dep[v] = dep[u] + w[i];
dfs(v, u);
}
}
void tarjan(int u, int f = 0){
for(int i = begin[u]; i; i = nxt[i]){
int v = to[i];
if(v == f) continue;
tarjan(v, u);
fa[v] = u;
}
vis[u] = 1;
for(int i = begin_[u]; i; i = nxt_[i]){
int v = to_[i];
if(vis[v]){
w_[i] = dep[u] + dep[v] - 2*dep[find(v)];
if(i&1) w_[i+1] = dep[u] + dep[v] - 2*dep[find(v)];
else w_[i-1] = dep[u] + dep[v] - 2*dep[find(v)];
}
}
}
int main(){
n = read<int>();
init();
for(int i = 1; i < n; ++i){
int x, y, z;
x = read<int>()+1;
y = read<int>()+1;
z = read<int>();
add(x, y, z);
add(y, x, z);
}
dfs(1);
//for(int i = 1; i <= n; ++i) printf("%d ", dep[i]);
m = read<int>();
for(int i = 1; i <= m; ++i){
int x, y;
x = read<int>()+1;
y = read<int>()+1;
add_(x, y);
add_(y, x);
}
tarjan(1);
for(int i = 1; i <= e_; i+=2){
printf("%d\n", w_[i]);
}
return 0;
}
LCA(包含RMQ)的更多相关文章
- LCA和RMQ
下面写提供几个学习LCA和RMQ的博客,都很通熟易懂 http://dongxicheng.org/structure/lca-rmq/ 这个应该是讲得最好的,且博主还有很多其他文章,可以读读,感觉认 ...
- ZOJ 3195 Design the city LCA转RMQ
题意:给定n个点,下面n-1行 u , v ,dis 表示一条无向边和边权值,这里给了一颗无向树 下面m表示m个询问,问 u v n 三点最短距离 典型的LCA转RMQ #include<std ...
- [CF 191C]Fools and Roads[LCA Tarjan算法][LCA 与 RMQ问题的转化][LCA ST算法]
参考: 1. 郭华阳 - 算法合集之<RMQ与LCA问题>. 讲得很清楚! 2. http://www.cnblogs.com/lazycal/archive/2012/08/11/263 ...
- lca转RMQ
这个博客写得好 #include <stdio.h> #include <vector> #include <string.h> using namespace s ...
- HDU 3078 LCA转RMQ
题意: n个点 m个询问 下面n个数字表示点权值 n-1行给定一棵树 m个询问 k u v k为0时把u点权值改为v 或者问 u-v的路径上 第k大的数 思路: LCA转RMQ求出 LCA(u,v) ...
- 【51NOD1766】树上的最远点对(线段树,LCA,RMQ)
题意:n个点被n-1条边连接成了一颗树,给出a~b和c~d两个区间, 表示点的标号请你求出两个区间内各选一点之间的最大距离,即你需要求出max{dis(i,j) |a<=i<=b,c< ...
- POJ 1986(LCA and RMQ)
题意:给定一棵树,求任意两点之间的距离. 思路:由于树的特殊性,所以任意两点之间的路径是唯一的.u到v的距离等于dis(u) + dis(v) - 2 * dis(lca(u, v)); 其中dis( ...
- LCA与RMQ
一.什么是LCA? LCA:Least Common Ancestors(最近公共祖先),对于一棵有根树T的任意两个节点u,v,求出LCA(T, u, v),即离跟最远的节点x,使得x同时是u和v的祖 ...
- HDU 5266 pog loves szh III (线段树+在线LCA转RMQ)
题目地址:HDU 5266 这题用转RMQ求LCA的方法来做的很easy,仅仅须要找到l-r区间内的dfs序最大的和最小的就能够.那么用线段树或者RMQ维护一下区间最值就能够了.然后就是找dfs序最大 ...
随机推荐
- 快速定位XPATH
本文主要介绍如何快速定位WEB端的xpath. 浏览器:Chrome.火狐浏览器 两种浏览器的定位方法都是一样:按F12键,可查看开发者工具 上图,开发者工具最左上角是定位按钮,点击此按钮,再点击浏览 ...
- InnoDB-MVCC与乐观锁
最近通过<高性能MySQL>一书学习MySQL方面的知识,在看到书中所讲InnoDB-MVCC部分的时候,有一种强烈的感觉,这不就是乐观锁吗(入门级小学徒的疑惑脸)?当下便去网上以各种方式 ...
- pycharm实用快捷键集锦
以下是本人需要记录的快捷键,并不针对大众,所以是断断续续补充的,大家看看图个乐呵就成! 生成代码块(Surround with):Ctrl + Alt + t . 历史浏览页面跳转:很多时候,我们需要 ...
- Bootstrap模态框钩子事件
事件类型 描述show.bs.modal show 方法调用之后立即触发该事件.如果是通过点击某个作为触发器的元素,则此元素可以通过事件的 relatedTarget 属性进行访问.shown.b ...
- BootStrap顺序验证和指定字符个数发送请求
fields: { curPwd: { verbose: false, //代表验证按顺序验证.验证成功才会下一个(验证成功才会发最后一个remote远程验证) threshold: 6,//有6字符 ...
- 【转】浅析Java中的final关键字
谈到final关键字,想必很多人都不陌生,在使用匿名内部类的时候可能会经常用到final关键字.另外,Java中的String类就是一个final类,那么今天我们就来了解final这个关键字的用法. ...
- 【转载】Vue自定义指令实现pc端加载更多
转载来源:https://www.86886.wang/detail/5a6f19e644f9da55274c3bbd,谢谢作者分享! 原理 document.documentElement.scro ...
- Groovy闭包
定义 闭包(Closure)是一种数据类型,它代表一段可执行的代码.它可以作为方法的参数,或者返回值,也可以独立运行,定义如下: def xxx = {parameters -> code} ...
- Python 爬虫 58同城
目标站点需求分析 获取各类产品的名字,地区,时间,价格 涉及的库 BeautifulSoup,requests,time,pymongo 获取各大类产品的链接 获取单页源码 解析单页源码 保存到文件中 ...
- SpringBoot图片上传(四) 一个input上传N张图,支持各种类型
简单介绍:需求上让实现,图片上传,并且可以一次上传9张图,图片格式还有要求,网上找了一个测试了下,好用,不过也得改,仅仅是实现了功能,其他不尽合理的地方,还需自己打磨. 代码: //html<d ...