codeforces CF983E NN country 树上倍增

$ \rightarrow $戳我看原题

  • 给定一棵树和若干条路线,每条路线相当于$ x,y $ 之间的路径,途径路径上的每个点

  • 给出若干个询问,每次询问从 $ u $ 到 $ v $ 至少需要利用几条路线

  • $ N,M,Q \le 200000 $


  • 倍增对问题进行转化

  • 对于每个店,求出只用一条路线向上能够到达的最高点$ lowest[x] $

  • 对 $ lowest $ 构造倍增数组

  • 对于询问 $ (u,v) $ ,倍增到 $ u^1 , v^1 $ 后,只需要检查 $ u^1 $ 到 $ v^1 $ 是否有跨越 $ lca(u,v) $ 的直达路线

  • 计算两点是否有直达路线

  • 树状数组维护\(DFS\)

  • \(DFS\)遍历整棵树,递归进入 \(x\) 时,扫描路线$ (x,y) $,把 $ y $ 在 \(DFS\) 序上的对应位置 \(+1\)

  • $ x,y $ 可直达,当且仅当 $ x $ 子树中的节点使 \(DFS\) 序上 $ y $ 对应的区间的和发生了变化

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
using namespace std;
#define maxn 200010
#define pb(x) push_back(x)
#define PP pair<int,int>
#define mp(a,b) make_pair(a,b)
#define fi first
#define se second
#define debug cout<<1<<endl;
int n,m,Q,ans[maxn];
inline int read() {
    register char ch;
    while(!isdigit(ch=getchar()));
    register int x=ch^'0';
    while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0');
    return x;
}
namespace BIT{
    int c[maxn];
    inline void add(int x,int val){
        for(;x<=n;x+=x&-x) c[x]+=val;
    }
    inline int qry(int x){
        int res=0;
        for(;x;x-=x&-x) res+=c[x];
        return res;
    }
}
namespace Union{
    int f[maxn];
    inline void init(int n){
        for(int i=1;i<=n;++i) f[i]=i;
    }
    int find(int x){ 
        return x==f[x] ? x : f[x]=find(f[x]);
    }
    inline void merge(int u,int v){
        f[u]=v;
    }
}
struct edge{ int v,nxt; }e[maxn<<1];
int heade[maxn],tote=1;
void adde(int u,int v){
    e[++tote].v=v; e[tote].nxt=heade[u]; heade[u]=tote;
}
struct buss{ int v,nxt; }b[maxn<<1];
int headb[maxn],totb=1,LCA_b[maxn<<1];
void addb(int u,int v){
    b[++totb].v=v; b[totb].nxt=headb[u]; headb[u]=totb;
}
struct querys{ int u,v,nxt; }q[maxn<<1];
int headq[maxn],totq=1,LCA_q[maxn<<1];
void addq(int u,int v){
    q[++totq].v=v; q[totq].u=u; q[totq].nxt=headq[u]; headq[u]=totq;
}
struct Querys{ int v,nxt; }Qs[maxn<<1];
int headQ[maxn],totQ=1,LCA_Q[maxn<<1];
void addQ(int u,int v){
    Qs[++totQ].v=v; Qs[totQ].nxt=headQ[u]; headQ[u]=totQ;
}
PP dfslen[maxn];
bool vis[maxn];
int dep[maxn],dfn;
void dfs(int u,int pre){
    vis[u]=1;
    dfslen[u].fi=++dfn;
    for(int i=heade[u];i;i=e[i].nxt)
        if(!vis[e[i].v]){
            int v=e[i].v;
            dep[v]=dep[u]+1;
            dfs(v,u);
            Union::merge(v,u);
        }
    dfslen[u].se=dfn;
    for(int i=headb[u];i;i=b[i].nxt)
        if(vis[b[i].v]) LCA_b[i]=LCA_b[i^1]=Union::find(b[i].v);
    for(int i=headq[u];i;i=q[i].nxt)
        if(vis[q[i].v]) LCA_q[i]=LCA_q[i^1]=Union::find(q[i].v);
}
int lowest[maxn][21];
void getlowest(int u){
    vis[u]=1; lowest[u][0]=u;
    for(int i=headb[u];i;i=b[i].nxt)
        if(dep[LCA_b[i]]<dep[lowest[u][0]] || lowest[u][0]==0) 
            lowest[u][0]=LCA_b[i];
    
    for(int i=heade[u];i;i=e[i].nxt)
        if(!vis[e[i].v]){
            int v=e[i].v;
            getlowest(v);
            if(dep[lowest[v][0]]<dep[lowest[u][0]]) 
                lowest[u][0]=lowest[v][0];
        }
}
void dfs2(int u){
    vis[u]=1; vector<PP>Qtmp;
    for(int i=headQ[u];i;i=Qs[i].nxt){
        int v=Qs[i].v;
        if(dfslen[v].fi>dfslen[u].fi && ans[i>>1]!=-1)
            Qtmp.pb(mp(i,BIT::qry(dfslen[v].se)-BIT::qry(dfslen[v].fi-1)));
    }
    for(int i=heade[u];i;i=e[i].nxt)
        if(!vis[e[i].v]) dfs2(e[i].v);
        
    for(int i=headb[u];i;i=b[i].nxt){
        BIT::add(dfslen[b[i].v].fi,1);
        BIT::add(dfslen[u     ].fi,1);
    }
    for(int i=0;i<Qtmp.size();++i){
        int tmp=BIT::qry(dfslen[Qs[Qtmp[i].fi].v].se)-BIT::qry(dfslen[Qs[Qtmp[i].fi].v].fi-1);
        ans[Qtmp[i].fi>>1]+=(Qtmp[i].se!=tmp ? 1 : 2);
    }
}
int main(){
    n=read();
    for(int i=2;i<=n;++i){
        int v; v=read();
        adde(i,v); adde(v,i);
    }
    scanf("%d",&m);
    for(int i=1;i<=m;++i){
        int u,v; u=read(); v=read();
        addb(u,v); addb(v,u);
    }
    scanf("%d",&Q);
    for(int i=1;i<=Q;++i){
        int u,v; u=read(); v=read();
        addq(u,v); addq(v,u);
    }
    Union::init(n); 
    dfs(1,0); 
    memset(vis,0,sizeof(bool)*(n+1));
    getlowest(1);
    for(int i=1;i<=n;++i)
    for(int j=1;j<=20;++j)
        lowest[i][j]=lowest[lowest[i][j-1]][j-1];
    for(int i=2;i<=totq;i+=2){
        int u=q[i].u,v=q[i].v;
        int tmp=0; 
        for(int j=20;~j;--j)
            if(dep[lowest[u][j]]>dep[LCA_q[i]]){
                u=lowest[u][j];
                tmp+=(1<<j);
            }
        for(int j=20;~j;--j)
            if(dep[lowest[v][j]]>dep[LCA_q[i]]){
                v=lowest[v][j];
                tmp+=(1<<j);
            }
        addQ(u,v); LCA_Q[totQ]=LCA_q[i];
        addQ(v,u); LCA_Q[totQ]=LCA_q[i];
        if(dep[lowest[u][0]]<=dep[LCA_Q[i]] && dep[lowest[v][0]]<=dep[LCA_Q[i]]) 
             ans[i>>1]=tmp;
        else ans[i>>1]=-1;
    }
    memset(vis,0,sizeof(bool)*(n+1));
    dfs2(1);
    for(int i=1;i<=Q;++i) printf("%d\n",ans[i]);
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/PotremZ/p/9416225.html
今日推荐