pog在与szh玩游戏,首先pog在纸上画了一棵有根树,这里我们定义1为这棵树的根,然后szh在这棵树中选了若干个点,想让pog帮忙找找这些点的最近公共祖先在哪里,一个点为S的最近公共祖先当且仅当以该点为根的子树包含S中的所有点,且该点深度最大。然而,这个问题是十分困难的,出于szh对pog的爱,他决定只找编号连续的点,即li ~ri 。
若干组数据(不超过3 组n≥10000 或Q≥10000 )。 每组数据第一行一个整数n(1≤n≤300000) ,表示树的节点个数。 接下来n?1 行,每行两个数Ai,Bi ,表示存在一条边连接这两个节点。 接下来一行一个数Q(1≤Q≤300000) ,表示有Q 组询问。 接下来Q行每行两个数li,ri(1≤li≤ri≤n) ,表示询问编号为li ~ri 的点的最近公共祖先。
对于每组的每个询问,输出一行,表示编号为li~ri的点的最近公共祖先的编号。
5 1 2 1 3 3 4 4 5 5 1 2 2 3 3 4 3 5 1 5
1 1 3 3 1
珍爱生命,远离爆栈。
预处理之后LCA是O(1)的,然后用线段树就能在logn的时间里得出询问结果啦!
#pragma comment(linker, "/STACK:102400000,102400000")
#include <cstdio>
#include <vector>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int maxn = 3e5 + 10;
const int inf = 1e8;
int pos[maxn],depth[maxn],head[maxn];
int d[maxn<<1][20],width[maxn<<1],tot,e;
typedef pair<int,int> Edge;
Edge edges[maxn<<1];
void AddEdge(int u,int v)
{
edges[++e] = make_pair(v,head[u]);head[u] = e;
edges[++e] = make_pair(u,head[v]);head[v] = e;
}
void pre(int u,int fa,int dep = 0)
{
d[++tot][0] = u;
if(!pos[u]) {
pos[u] = tot;
depth[u] = dep;
}
for(int eid = head[u]; eid ; eid = edges[eid].second) {
int &v = edges[eid].first;
if(v==fa)continue;
pre(v,u,dep+1);
d[++tot][0] = u;
}
}
void RMQ_init(int n)
{
for(int j = 1; (1<<j) <= n; j++) {
for(int i = 1; i + (1<<j) - 1 <= n; i++) {
d[i][j] = depth[d[i][j-1]] < depth[d[i+(1<<(j-1))][j-1]] ? d[i][j-1] : d[i+(1<<(j-1))][j-1];
}
}
for(int i = 1,w = 1; i <= n; i++) {
if((1<<w) <= i) w++;
width[i] = w;
}
}
int LCA(int u,int v)
{
int L = pos[u],R = pos[v];
if(L > R) swap(L,R);
int k = width[R-L+1] - 1;
return depth[d[L][k]] < depth[d[R-(1<<k)+1][k]] ? d[L][k] : d[R-(1<<k)+1][k];
}
int seg[maxn<<1];
void built(int o,int L,int R)
{
if(L==R) {
seg[o] = L;
return;
}
int mid = (L + R) >> 1;
built(o<<1,L,mid);
built(o<<1|1,mid+1,R);
seg[o] = LCA(seg[o<<1],seg[o<<1|1]);
}
int ql,qr;
int Query(int o,int L,int R)
{
if(ql<=L&&qr>=R) {
return seg[o];
}
int mid = (L + R) >> 1;
int ans = -1;
if(ql <= mid) ans = Query(o<<1,L,mid);
if(qr > mid) {
int t = Query(o<<1|1,mid+1,R);
if(ans==-1) ans = t;
else ans = LCA(ans,t);
}
return ans;
}
int main(int argc, char const *argv[])
{
int n;
while(scanf("%d",&n)==1) {
memset(head,0,sizeof(head[0])*(n+1));
for(int i = 1; i < n; i++) {
int u, v;scanf("%d%d",&u,&v);
AddEdge(u,v);
}
e = tot = 0;
memset(pos,0,sizeof(pos[0])*(n+1));
pre(1,-1);
RMQ_init(tot);
built(1,1,n);
int Q;scanf("%d",&Q);
while(Q--) {
scanf("%d%d",&ql,&qr);
if(ql > qr) swap(ql,qr);
printf("%d\n", Query(1,1,n));
}
}
return 0;
}
原文地址:http://blog.csdn.net/acvcla/article/details/46586911