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序最大 ...
随机推荐
- Windows系统下查看某一进程下所有线程的dos命令
1.查看进程 pslist或 tasklist 注:若出现“pslist不是外部或内部命令,也不是可运行的程序....”,需要去TechNet官网下载psTools(链接https://technet ...
- java8 按对象属性值排序
//按id从小到大 List<User> sortUser = list.stream().sorted((u1, u2) -> u1.getId().compareTo(u2.ge ...
- Numpy 学习(一)
1.Numpy 中Matrices和arrays的区分 Numpy matrices必须是2维的,但是 numpy arrays (ndarrays) 可以是多维的(1D,2D,3D····ND). ...
- gulp学习笔记——最好的学习文档是官网
官网:http://www.gulpjs.com.cn/docs/api/ 当然还有一个博客写的也很好,当我看不下去官网的时候,这个帮助了我很多,明了易懂:http://www.ydcss.com/a ...
- JAVA进阶7
间歇性混吃等死,持续性踌躇满志系列-------------第7天 1.Map接口的常用方法 import java.util.HashMap; import java.util.Map; publi ...
- Invalid character found in the request target. The valid characters are defined in RFC 7230 and RFC
解决Invalid character found in the request target. The valid characters are defined in RFC 7230 and RF ...
- # 20175333曹雅坤《Java程序设计》第1周学习总结
教材学习内容总结 1.学习第一章PPT,安装JRE,JDK并配置path环境参数 2.在windows上使用dos命令运行教材第一章代码Hello.java和People.java 3.下载使用git ...
- windows下使用git和github建立远程仓库
转自(http://www.bubuko.com/infodetail-430228.html) 从昨天开始就在看git的使用,因为在Windows下很多命令行操作都比较坑爹,但是今天再走了无数弯路之 ...
- CSS圆环百分比DEMO
<html> <head> <title>test</title><!--本DEMO参考http://www.cnblogs.com/jr1993 ...
- 【原创】大数据基础之Zookeeper(2)源代码解析
核心枚举 public enum ServerState { LOOKING, FOLLOWING, LEADING, OBSERVING; } zookeeper服务器状态:刚启动LOOKING,f ...