[CF1062E] Company

题意

Here

思考

最重要的问题在于,我们删去哪个点后,剩下点的公共 \(LCA\) 深度最大,即如何确定这个点。我们感性的观察和理性的分析之后,发现和点的 \(dfn\) 序有关系,要么删去当前区间点 \(dfn\) 最大的,要么删最小的。

如果得出上面那个结论就好办了,拿个线段树维护区间 \(dfn\) 的最大和最小值,选择是删 \(dfn\) 最大的点还是最小的点即可。

代码

#include<bits/stdc++.h>
#define ls(pos) pos << 1
#define rs(pos) pos << 1 | 1
using namespace std;
const int N = 100010;
const int M = 100010;
struct node{
    int nxt, to;
}edge[M << 1];
int head[N], num;
void build(int from, int to){
    edge[++num].nxt = head[from];
    edge[num].to = to;
    head[from] = num;
}
int dfn[N], cnt, f[N][20], rev[N], d[N], n, q;
namespace Seg{
    int Max[N << 2], Min[N << 2];
    void pushup(int pos){
        Max[pos] = max( Max[ls(pos)], Max[rs(pos)] );
        Min[pos] = min( Min[ls(pos)], Min[rs(pos)] );
    }
    void build(int pos, int l, int r){
        if(l == r){
            Max[pos] = Min[pos] = dfn[l];
            return;
        }
        int mid = (l + r) >> 1;
        build(ls(pos), l, mid);
        build(rs(pos), mid+1, r);
        pushup(pos);
    }
    void modify(int pos, int l, int r, int x, int v){
        if(l == r && l == x){
            Max[pos] = max(Max[pos], v);
            Min[pos] = min(Min[pos], v);
            return;
        }
        int mid = (l + r) >> 1;
        if(x <= mid) modify(ls(pos), l, mid, x, v);
        else modify(rs(pos), mid+1, r, x, v);
        pushup(pos);
    }
    int QMAX(int pos, int l, int r, int x, int y){
        int ans = 0;
        if(l > y || r < x) return 0;
        if(x <= l && r <= y) return Max[pos];
        int mid = (l + r) >> 1;
        if(x <= mid) ans = max(ans, QMAX(ls(pos), l, mid, x, y));
        if(y > mid) ans = max(ans, QMAX(rs(pos), mid+1, r, x, y));
        return ans;
    }
    int QMIN(int pos, int l, int r, int x, int y){
        int ans = 0x3f3f3f3f;
        if(l > y || r < x) return 0x3f3f3f3f;
        if(x <= l && r <= y) return Min[pos];
        int mid = (l + r) >> 1;
        if(x <= mid) ans = min(ans, QMIN(ls(pos), l, mid, x, y));
        if(y > mid) ans = min(ans, QMIN(rs(pos), mid+1, r, x, y));
        return ans;
    }
}
using namespace Seg;
void dfs(int u, int fa){
    dfn[u] = ++cnt; rev[cnt] = u;
    for(int i=head[u]; i; i=edge[i].nxt){
        int v = edge[i].to;
        if(v == fa) continue;
        d[v] = d[u] + 1;
        f[v][0] = u;
        dfs(v, u);
    }
}
int lca(int u, int v){
    if(d[u] < d[v]) swap(u, v);
    for(int i=18; i>=0; i--) if(d[f[u][i]] >= d[v]) u = f[u][i];
    if(u == v) return u;
    for(int i=18; i>=0; i--) if(f[u][i] != f[v][i]) u = f[u][i], v = f[v][i];
    return f[u][0];
}
int main(){
    cin >> n >> q;
    for(int i=2; i<=n; i++){
        int v; cin >> v;
        build(i, v); build(v, i);
    }
    d[1] = 1;
    dfs(1, 0);
    build(1, 1, n);
    for(int j=1; j<=18; j++)
        for(int i=1; i<=n; i++) f[i][j] = f[f[i][j-1]][j-1];
    while(q --){
        int l, r, L, Lu, R, Ru, L2, L2u, R2, R2u, LCA1, LCA2;
        int flag = 0;
        cin >> l >> r;
        L = QMIN(1, 1, n, l, r), R = QMAX(1, 1, n, l, r);
        Lu = rev[L], Ru = rev[R];
        L2 = min(QMIN(1, 1, n, l, Lu - 1), QMIN(1, 1, n, Lu + 1, r));
        R2 = max(QMAX(1, 1, n, l, Ru - 1), QMAX(1, 1, n, Ru + 1, r));
        L2u = rev[L2], R2u = rev[R2];
        LCA1 = lca(Lu, R2u); LCA2 = lca(L2u, Ru);
        if(d[LCA1] > d[LCA2]) flag = 1;
        else flag = 0;
        if(flag){
            cout << Ru << " " << d[LCA1] - 1 << endl;
        }
        else cout << Lu << " " << d[LCA2] - 1 << endl;
    }
    return 0;
}

总结

大概猜出第一个结论就好做了。

posted @ 2018-11-20 23:33  alecli  阅读(162)  评论(0编辑  收藏  举报