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