1. 程式人生 > 其它 >“20121-2022-1學期20212322劉海浩《網路空間安全專業導論》第二週學習總結”

“20121-2022-1學期20212322劉海浩《網路空間安全專業導論》第二週學習總結”

題解

搞一個尤拉序出來,先考慮刪點,設某個點 \(x\) 在尤拉序上第一次出現的位置為 \(fst_x\),最後一次出現的位置為 \(lst_x\),那麼刪掉的點就是 \(\{a|\min\limits_{i=l}^{i\leq r}(fst_i)=fst_a\lor\max\limits_{i=l}^{i\leq r}(lst_i)=lst_a\}\),也就是 \(fst_a\) 最小或 \(lst_a\) 最大。

對每個點找一下 \(fst,lst\),然後建出兩個 ST 表分別維護區間 \(\min\)\(\max\) 的位置就可以 \(O(1)\) 找到被刪掉的兩個點。

刪掉一個點之後,\([l,r]\)

被分成了兩個區間,先在剩下的部分裡找 \(\min(fst_x)\)\(\max(lst_x)\),然後根據 \(dep_{LCA}=\min\limits_{i=L}^{i\leq R}{dep_i}\),在尤拉序上查詢 \([\min(fst_x),\max(lst_x)]\) 這個區間的 \(\max(dep)\) 就能得到 LCA 的深度了,這部分用 ST 表解決,時間複雜度 \(O(1)\)

注意我們建了三個 ST 表,分別維護的是節點序列的 \(fst\) 值、\(lst\) 值和尤拉序上的 \(dep\) 值,所以時間複雜度是 \(O(n\log n+q)\)

程式碼

#include<bits/stdc++.h>
using namespace std;
using ll=long long;
inline int qread(){
    int ret=0;char buf=getchar();bool neg=false;
    while(!isdigit(buf)){if(buf=='-'){neg=true;}buf=getchar();}
    while(isdigit(buf)){ret=ret*10+buf-'0';buf=getchar();}
    return neg?-ret:ret;
}

vector<int> Es[100005];
void addE(int fr,int to){
    Es[fr].emplace_back(to);
}

int dep[100005];
int eula[200005];
int idx=0;
int lb[100005],rb[100005];

void dfs(int nw,int fa){
    dep[nw]=dep[fa]+1;
    eula[++idx]=dep[nw];
    lb[nw]=idx;
    rb[nw]=idx;
    for(auto it:Es[nw]){
        if(it==fa) continue;
        dfs(it,nw);
        eula[++idx]=dep[nw];
        rb[nw]=idx;
    }
}

int logn[200005];

void pre(int n){
    logn[1]=0;logn[2]=1;
    for(int i=3;i<n;i++) logn[i]=logn[i>>1]+1;
}


struct EST{ // if min == frm[pos], return frm[pos];
    int st[18][200005];
    void init(int* frm,int len){
        memset(st,0x33,sizeof(st));
        for(int i=1;i<=len;i++) st[0][i]=frm[i];
        for(int j=1;j<=17;j++)
            for(int i=1;i<=len;i++)
                st[j][i]=min(st[j-1][i],st[j-1][max(i-(1<<(j-1)),1)]);
    }
    int RMinQ(int l,int r){
        int j=logn[r-l+1];
        return min(st[j][r],st[j][max(l-1+(1<<j),1)]);
    }
}est;

struct PST{ // if min/max == ffr[pos], return pos;
    int st[17][100005];
    int* ffr=NULL;
    bool mint=true; // true --> get min_pos, false --> get max_pos
    void init(int* frm,int len,bool minv){
        mint=minv;
        ffr=frm;
        memset(st,0x33,sizeof(st));
        for(int i=0;i<=len;i++) st[0][i]=i;
        if(mint)
            for(int j=1;j<=16;j++)
                for(int i=1;i<=len;i++)
                    if(frm[st[j-1][i]]<frm[st[j-1][max(i-(1<<(j-1)),1)]]) st[j][i]=st[j-1][i];
                    else st[j][i]=st[j-1][max(i-(1<<(j-1)),1)];
        else
            for(int j=1;j<=16;j++)
                for(int i=1;i<=len;i++)
                    if(frm[st[j-1][i]]>frm[st[j-1][max(i-(1<<(j-1)),1)]]) st[j][i]=st[j-1][i];
                    else st[j][i]=st[j-1][max(i-(1<<(j-1)),1)];
    }
    int RMQ(int l,int r){
        int j=logn[r-l+1];
        if(mint)
            if(ffr[st[j][r]]<ffr[st[j][max(l-1+(1<<j),1)]]) return st[j][r];
            else return st[j][max(l-1+(1<<j),1)];
        else
            if(ffr[st[j][r]]>ffr[st[j][max(l-1+(1<<j),1)]]) return st[j][r];
            else return st[j][max(l-1+(1<<j),1)];
    }
}ltt,rtt;

int main(){
    int n=qread(),q=qread();
    for(int i=1;i<=n-1;i++){
        int lt=qread();
        addE(i+1,lt);
        addE(lt,i+1);
    }
    dep[0]=-1;
    dfs(1,0);
    pre(idx);
    est.init(eula,idx);
    ltt.init(lb,n,true);
    rtt.init(rb,n,false);
    for(int i=1;i<=q;i++){
        int l=qread(),r=qread();
        int lp=ltt.RMQ(l,r),lpdep;
        {int dfsmin=9982443,dfsmax=-1;
        if(lp!=l){
            dfsmin=min(dfsmin,lb[ltt.RMQ(l,lp-1)]);
            dfsmax=max(dfsmax,rb[rtt.RMQ(l,lp-1)]);
        }
        if(lp!=r){
            dfsmin=min(dfsmin,lb[ltt.RMQ(lp+1,r)]);
            dfsmax=max(dfsmax,rb[rtt.RMQ(lp+1,r)]);
        }
        lpdep=est.RMinQ(dfsmin,dfsmax);}
        int rp=rtt.RMQ(l,r),rpdep;
        {int dfsmin=9982443,dfsmax=-1;
        if(rp!=l){
            dfsmin=min(dfsmin,lb[ltt.RMQ(l,rp-1)]);
            dfsmax=max(dfsmax,rb[rtt.RMQ(l,rp-1)]);
        }
        if(rp!=r){
            dfsmin=min(dfsmin,lb[ltt.RMQ(rp+1,r)]);
            dfsmax=max(dfsmax,rb[rtt.RMQ(rp+1,r)]);
        }rpdep=est.RMinQ(dfsmin,dfsmax);}
        int ans=lpdep>rpdep?lp:rp;
        printf("%d %d\n",ans,max(lpdep,rpdep));
    }
}