Codeforces Round #520 (Div. 2) E Company

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;
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值