Codeforces Round #520 (Div. 2) E Company
题意
给定一棵树,树上结点编号为1,n,有q个询问,每一个询问给定一个区间,对于每一个区间(区间长度大于等于2),删除一个节点后,使得剩下这个区间的LCA的深度最大,输出删除的节点与LCA的深度
分析
先修知识: LCA,RMQ,DFS序
[l,r] 区间的lca其实就是DFS序最小和DFS序最大的两个的LCA,所以我们删除这两个节点,求剩下的LCA就OK了,具体看代码
#include<cstdio>
#include<cstring>
#include<vector>
#include<cmath>
#include<iostream>
using namespace std;
const int INF = 1e8;
const int maxn = 1e5+100;
const int maxlogv = 20;
struct Edge{
int to,weight;
Edge(int t,int w):to(t),weight(w){};
};
vector<Edge> G[maxn];
typedef pair<int,int> P;
#define FI first
#define SE second
int id[maxn];
int vs[maxn*2],depth[maxn*2];
int dp[maxn*2][maxlogv];
int dpmin[maxn*2][maxlogv];
int dpmax[maxn*2][maxlogv];
void dfs(int node,int fa,int d,int &k){
id[node] = k;
vs[k] = node;
depth[k++] = d;
// dis[node] = distance;
for(int i = 0;i < (int)G[node].size(); ++i){
Edge &t = G[node][i];
if(t.to == fa) continue;
// dis[t.to] = dis[node]+t.weight;
dfs(t.to,node,d+1,k);
vs[k] = node;
depth[k++] = d;
}
}
void init_rmq(int n){
for(int i = 0;i < n ; ++i) dp[i][0] = i;
for(int j = 1;(1<<j) <= n; ++j){
for(int i = 0;i + (1<<j)-1 < n; ++i){
if(depth[dp[i][j-1]]< depth[dp[i+(1<<(j-1))][j-1]])
dp[i][j] = dp[i][j-1];
else
dp[i][j] = dp[i+(1<<(j-1))][j-1];
}
}
}
int query(int l,int r){
int k = 0;
while((1<<(k+1)) <= r-l+1) k++;
if(depth[dp[l][k]] < depth[dp[r-(1<<k)+1][k]])
return dp[l][k];
else
return dp[r-(1<<k)+1][k];
}
int lca(int u,int v){
return vs[query(min(id[u],id[v]),max(id[u],id[v]))];
}
void INIT_RMQ_MIN(int n){
for(int i = 0;i < n ; ++i) dpmin[i][0] = i;
for(int j = 1;(1<<j) <= n; ++j){
for(int i = 0;i + (1<<j)-1 < n; ++i){
if(id[dpmin[i][j-1]]< id[dpmin[i+(1<<(j-1))][j-1]])
dpmin[i][j] = dpmin[i][j-1];
else
dpmin[i][j] = dpmin[i+(1<<(j-1))][j-1];
}
}
}
void INIT_RMQ_MAX(int n){
for(int i = 0;i < n ; ++i) dpmax[i][0] = i;
for(int j = 1;(1<<j) <= n; ++j){
for(int i = 0;i + (1<<j)-1 < n; ++i){
if(id[dpmax[i][j-1]] > id[dpmax[i+(1<<(j-1))][j-1]])
dpmax[i][j] = dpmax[i][j-1];
else
dpmax[i][j] = dpmax[i+(1<<(j-1))][j-1];
}
}
}
P query1(int l,int r){
int k = 0;
while((1<<(k+1)) <= r-l+1) k++;
P ans;
if(id[dpmin[l][k]] < id[dpmin[r-(1<<k)+1][k]])
ans.first = dpmin[l][k];
else
ans.first = dpmin[r-(1<<k)+1][k];
if(id[dpmax[l][k]] > id[dpmax[r-(1<<k)+1][k]])
ans.second = dpmax[l][k];
else
ans.second = dpmax[r-(1<<k)+1][k];
return ans;
}
void init(int n){
int k = 0;
dfs(0,-1,0,k);
init_rmq(2*n-1);
INIT_RMQ_MIN(n);
INIT_RMQ_MAX(n);
}
int remove(int u,int l,int r){
P a,b;
if(u-1 >= l)
a = query1(l,u-1);
if(u+1 <= r)
b = query1(u+1,r);
P tmp;
if(u + 1 > r)
{
tmp = a;
return depth[id[lca(tmp.FI,tmp.SE)]];
}
if(u-1 < l){
tmp = b;
return depth[id[lca(tmp.FI,tmp.SE)]];
}
tmp.first =vs[ min(id[a.first],id[b.first])];
tmp.second = vs[max(id[a.second],id[b.second])];
// if(tmp.first == INF)
// return depth[id[tmp.second]];
// if(tmp.second == -1)
// return depth[id[tmp.first]];
// cout<<lca(tmp.FI,tmp.SE)+1<<endl;
return depth[id[lca(tmp.FI,tmp.SE)]];
}
int main(void){
int n,q;
while(~scanf("%d%d",&n,&q)){
for(int i = 0;i < n; ++i) G[i].clear();
// int u,v,w;
for(int i = 1,u;i < n; ++i)
{
scanf("%d",&u);
u--;
// cout<<u<<" ";
G[u].push_back(Edge(i,1));
}
init(n);
// scanf("%d",&q);
// for(int i = 1;i <n; ++i)
// cout<<depth[i]<<" ";
// cout<<endl;
while(q--){
int u,v;
scanf("%d %d",&u,&v);
u--,v--;
P p = query1(u,v);
// cout<<"DEBUG"<<p.first+1<<" "<<p.second+1<<endl;
// cout<<p.first+1<<" "<<p.SE+1<<endl;
P ans;
int a = remove(p.first,u,v);
int b = remove(p.second,u,v);
// cout<<"DEBUG "<<depth[id[2]]<<endl;
if(a > b){
ans.first = p.first;
ans.second = a;
}
else{
ans.first = p.second;
ans.second = b;
}
// cout<<"DEBUG "<<depth[2]<<endl;
// cout<<a<<" "<<b<<endl;
printf("%d %d\n",ans.first+1,ans.second);
// int f = lca(u,v);
// printf("%d\n",dis[u]+dis[v]-2*dis[f]);
}
}
return 0;
}