CF 1062E Company题解
说在前面
这篇题解中用到的数据结构并非最优 可依照思路用其他数据结构完成(比如\(ST\)表)
题目描述
题目传送门~
给定一颗树,有若干个询问,每个询问给出 \(l\),\(r\),要求编号为 \(l\)~\(r\) 的点任意删去一个之后剩余点的 \(LCA\) 深度最大,输出删去点的编号和 \(LCA\) 的最大深度
算法分析
一个结论:求若干个点的\(LCA\)等同于求其\(dfn\)或者欧拉序最小和最大的\(LCA\)
我们可以用一个\(RMQ\)数据结构维护编号的区间欧拉序最小和最大的节点,这样就能轻松解决区间\(LCA\)啦!
可是删除一个点又该怎么处理?非常明显,根据上面的结论,无论我们删去除欧拉序最大最小的其他哪个点,区间\(LCA\)依旧是不变的,为了删去一个点让\(LCA\)深度变大,我们从欧拉序最大的和最小的里面选出一个删去就可以实现,两个删去后分别求\(LCA\),选择最低的便是答案
Code
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
#define PII pair<int, int>
const int N = 1e5+21;
typedef struct{
int to;
int nxt;
}Edge;
Edge edge[N*2];
int head[N];
int cnt;
inline void add_edge(int u, int v){
edge[cnt].to = v;
edge[cnt].nxt = head[u];
head[u] = cnt++;
return;
}
int tot;
int idx[N];
int dep[N*2];
int eu[N*2];
inline void dfs(int x, int fa, int deep){
idx[x] = ++tot;
eu[tot] = x;
dep[tot] = deep;
for(int i = head[x]; ~i; i = edge[i].nxt)
if(edge[i].to != fa){
dfs(edge[i].to, x, deep+1);
eu[++tot] = x;
dep[tot] = deep;
}
}
int tree[4][N*5];
inline int lchild(int x){return x<<1;}
inline int rchild(int x){return x<<1|1;}
inline void push_up(int x){
if(idx[tree[2][lchild(x)]] > idx[tree[2][rchild(x)]])
tree[2][x] = tree[2][rchild(x)];
else
tree[2][x] = tree[2][lchild(x)];
if(idx[tree[3][lchild(x)]] < idx[tree[3][rchild(x)]])
tree[3][x] = tree[3][rchild(x)];
else
tree[3][x] = tree[3][lchild(x)];
}
inline void build1(int p, int pl, int pr){
if(pl == pr){
tree[2][p] = tree[3][p] = pl;
return;
}
int mid = (pl+pr) >> 1;
build1(lchild(p), pl, mid);
build1(rchild(p), mid+1, pr);
push_up(p);
}
inline PII query1(int p, int pl, int pr, int l, int r){
if(pl >= l && pr <= r)
return make_pair(tree[2][p], tree[3][p]);
int mid = (pl+pr) >> 1;
int minn = 0, maxx = 0;
if(mid >= l){
PII x = query1(lchild(p), pl, mid, l, r);
if(!minn)
minn = x.first;
else if(idx[minn] > idx[x.first])
minn = x.first;
if(!maxx)
maxx = x.second;
else if(idx[maxx] < idx[x.second])
maxx = x.second;
}
if(mid < r){
PII x = query1(rchild(p), mid+1, pr, l, r);
if(!minn)
minn = x.first;
else if(idx[minn] > idx[x.first])
minn = x.first;
if(!maxx)
maxx = x.second;
else if(idx[maxx] < idx[x.second])
maxx = x.second;
}
return make_pair(minn, maxx);
}
int lg[N*2];
int dp[N*2][22];
inline void ST(){
for(int i = 1; i <= tot; i++)
lg[i] = lg[i-1] + (1<<lg[i-1] == i);
for(int i = 1; i <= tot; i++)
dp[i][0] = i;
for(int i = 1; (1<<i) <= tot; i++)
for(int j = 1; j + (1<<i) - 1 <= tot; j++){
int a = dp[j][i-1];
int b = dp[j+(1<<(i-1))][i-1];
dp[j][i] = dep[a] > dep[b] ? b : a;
}
return;
}
inline int LCA(int x, int y){
int l = idx[x];
int r = idx[y];
if(r < l)
swap(l, r);
int len = lg[r-l+1]-1;
int a = dp[l][len];
int b = dp[r-(1<<len)+1][len];
return dep[a] > dep[b] ? eu[b] : eu[a];
}
int n, q;
inline int Seg_LCA_Del(int l, int r, int x){
PII X;
int a = 0, b = 0;
if(l <= x-1){
X = query1(1, 1, n, l, x-1);
a = LCA(X.first, X.second);
}
if(x+1 <= r){
X = query1(1, 1, n, x+1, r);
b = LCA(X.first, X.second);
}
if(!a)
return b;
if(!b)
return a;
return LCA(a, b);
}
int main(){
memset(head, -1, sizeof(head));
scanf("%d%d", &n, &q);
for(int i = 2; i <= n; i++){
int x;
scanf("%d", &x);
add_edge(i, x);
add_edge(x, i);
}
dfs(1, 0, 1);
build1(1, 1, n);
ST();
while(q--){
int l, r;
scanf("%d%d", &l, &r);
PII p = query1(1, 1, n, l, r);
int x = p.first;
int y = p.second;
int a = Seg_LCA_Del(l, r, x);
int b = Seg_LCA_Del(l, r, y);
if(dep[idx[a]] > dep[idx[b]] || !b)
printf("%d %d\n", x, dep[idx[a]]-1);
else if(dep[idx[a]] <= dep[idx[b]] || !a)
printf("%d %d\n", y, dep[idx[b]]-1);
}
return 0;
}

浙公网安备 33010602011771号