Codeforces342 E. Xenia and Tree(分块)

题意:

给定n个顶点的树,一开始1号顶点是红色的,其他顶点是蓝色的
m次操作,操作有两种:
1.将一个红色点变成蓝色
2.给定x,查询到x最近的红色点的距离

数据范围:n,m<=1e5

解法:

没办法动态维护每个点到红色点的距离,
正解是将查询分块:
开一个mi[x]表示距离x的最近红色点距离,一开始就是距离点1的距离
对于操作1,将新染的红色点存到一个数组que[]里面不动,当满sq个的时候一次bfs更新
对于操作2,计算x到que[]里面的所有点的距离,对它们以及mi[x]取min就是当前答案。

操作2计算树上点对距离需要用到lca

解法参考:this

code:

#include<bits/stdc++.h>
using namespace std;
const int maxm=1e5+5;
const int sq=333;
int head[maxm],nt[maxm<<1],to[maxm<<1],cnt;
const int maxd=20;
int f[maxm][25];
int que[maxm],num;
int mark[maxm];
int mi[maxm];
int d[maxm];
int c[maxm];
int n,m;
void add(int x,int y){
    cnt++;nt[cnt]=head[x];head[x]=cnt;to[cnt]=y;
}
void dfs(int x,int fa){
    for(int i=1;i<=maxd;i++){
        f[x][i]=f[f[x][i-1]][i-1];
    }
    for(int i=head[x];i;i=nt[i]){
        int v=to[i];
        if(v==fa)continue;
        d[v]=d[x]+1;
        mi[v]=mi[x]+1;
        f[v][0]=x;
        dfs(v,x);
    }
}
int lca(int a,int b){
    if(d[a]<d[b])swap(a,b);
    for(int i=maxd;i>=0;i--){
        if(d[f[a][i]]>=d[b]){
            a=f[a][i];
        }
    }
    if(a==b)return a;
    for(int i=maxd;i>=0;i--){
        if(f[a][i]!=f[b][i]){
            a=f[a][i];
            b=f[b][i];
        }
    }
    return f[a][0];
}
int getd(int a,int b){
    return d[a]+d[b]-2*d[lca(a,b)];
}
void bfs(){//多源bfs计算每个点到红色点的距离
    queue<int>q;
    for(int i=1;i<=n;i++){
        if(c[i]){
            mi[i]=0;
            q.push(i);
            mark[i]=1;
        }else{
            mark[i]=0;
        }
    }
    while(!q.empty()){
        int x=q.front();q.pop();
        for(int i=head[x];i;i=nt[i]){
            int v=to[i];
            if(!mark[v]){
                mi[v]=mi[x]+1;
                q.push(v);
                mark[v]=1;
            }
        }
    }

}
signed main(){
    scanf("%d%d",&n,&m);
    for(int i=1;i<n;i++){
        int a,b;scanf("%d%d",&a,&b);
        add(a,b);add(b,a);
    }
    d[1]=1;
    mi[1]=0;
    c[1]=1;
    dfs(1,1);
    while(m--){
        int op,x;scanf("%d%d",&op,&x);
        if(op==1){
            que[++num]=x;
            c[x]=1;
            if(num==sq){
                bfs();
                num=0;
            }
        }else if(op==2){
            int ans=mi[x];
            for(int i=1;i<=num;i++){
                ans=min(ans,getd(x,que[i]));
            }
            printf("%d\n",ans);
        }
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/weixin_44178736/article/details/107814326
今日推荐