LCA(最近公共祖先)
适用题型:各种树
1.询问各节点间距离
2.询问节点祖孙关系
样题:
题目背景
SOURCE:NOIP2015-SHY
题目描述
给出一棵带有边权的树,问两点之间的距离。
输入格式
第一行两个整数 n 和 m ,分别表示点数和询问数。
接下来 n-1 行,每行三个整数 x,y,z,表示 x 与 y 通过一条权为 z 的边连接。
接下来 m 行,每行两个整数 x,y,代表一组询问。
输出格式
输出 m 行,每行一个整数,对应一组询问的答案。
样例数据 1
输入 [复制]
3 3
1 2 1
1 3 2
1 2
1 3
2 3
输出
1
2
3
备注
【数据范围】
对 30% 的输入数据 :1≤n,m≤1000
对 100% 的输入数据 :1≤n,m≤100000;1≤z≤10000
std.cpp:
//std answer of LCA
#include<iostream>
#include<iomanip>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#include<string>
#include<cstring>
#include<ctime>
using namespace std;
int n,m,x,y,z,cnt=0;
int dis[100010],first[100010],dep[100010],f[100010][25];
#define maxx n
bool vis[100010];
struct node{
int u,v,val,next;
}side[200010];
void addedge(int u,int v,int w)
{
cnt += 1;
side[cnt].u = u;
side[cnt].v = v;
side[cnt].val = w;
side[cnt].next = first[u];
first[u] = cnt;
}
void dfs(int x)
{
vis[x] = true;
for(int i=first[x];i;i=side[i].next)
{
int v = side[i].v;
if(!vis[v])
{
f[v][0] = x;
dis[v] = side[i].val + dis[x];
dep[v] = dep[x] + 1;
dfs(v);
}
}
}
int Init(int root)
{
memset(dep,0,sizeof(dep));
dep[root] = 0;
dis[root] = 0;
dfs(root);
for(int i=1;i<=20;i++)
for(int j=1;j<=maxx;j++)
if(f[j][i-1])
f[j][i] = f[f[j][i-1]][i-1];
}
int lca(int x,int y)
{
if(dep[x]<dep[y])
{
int k=x;x=y;y=k;
}
int foot = dep[x] - dep[y];
for(int i=18;i>=0;i--)
if(foot>=(1<<i)) foot -= (1<<i), x = f[x][i];
if(x==y) return x;
for(int i=18;i>=0;i--)
if(f[x][i]!=f[y][i]) x = f[x][i], y = f[y][i];
return f[x][0];
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(NULL);
cin >> n >> m;
for(int i=1;i<n;i++)
{
cin >> x >> y >> z;
addedge(x,y,z);
addedge(y,x,z);
}
Init(1);
for(int i=1;i<=m;i++)
{
cin >> x >> y;
int jud = lca(x,y);
cout << dis[x]+dis[y]-2*dis[jud] << endl;
}
}
RMQ(区间最值)
适用题型:各种区间最值
1.最大值
2.最小值
样题:
【问题描述】
现给你n(<=10^6)个整数(都小于longint),有k(0~10^6)个询问,对于每个询问(L,R),
回答(L,R)内的最大值为多少?
【输入格式】
输入共计两行。
第一行两个整数n 和k ;
第二行为n 个整数
第三行到第k+2 行为 k 个询问;
【输出格式】
输出文件共k 行,每行为一个询问的最大值;
【样例输入】
10 2
3 2 4 5 6 8 1 2 9 7
1 8
2 9
【样例输出】
8
9
std.cpp
#include<iostream>
#include<iomanip>
#include<cstdio>
#include<cstdlib>
#include<string>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
int n,k,l,r,num[1000005];
int f[1000005][23];
int st()
{
for(int i=1;i<=n;i++) f[i][0] = num[i];
for(int j=1;j<=int((log(n)/log(2)));j++)
for(int i=1;i+(1<<j)-1<=n;i++)
f[i][j] = max(f[i][j-1],f[i+(1<<(j-1))][j-1]);
}
int ask(int l,int r)
{
int k = int(log(r-l+1)/log(2));
return max(f[l][k],f[r+1-(1<<k)][k]);
}
int main()
{
cin >> n >> k;
for(int i=1;i<=n;i++) cin >> num[i];
st();
while(k--)
{
cin >> l >> r;
cout << ask(l,r) << endl;
}
}