码迷,mamicode.com
首页 > 其他好文 > 详细

【CodeForces】E. Xenia and Tree(分块 + LCA)

时间:2015-07-29 21:27:32      阅读:142      评论:0      收藏:0      [点我收藏+]

标签:

对于两个操作,对于操作1,每次储存要修改的点,直到存了sqrt(m)个点的时候进行更新,并将图重建一次(重新记录每个点到最近染色点的距离)

对于操作2,利用LCA求现在存着的点(也就是还没有更新到图上的点)和这个点的距离的最小值以及这个点在当前图中和最近的染色的那个点的距离。

话说LCA真是个好东西=  =!这几天补一补去

题解在这里:http://codeforces.com/blog/entry/8800

#include<cmath>
#include<queue>
#include<cstdio>
#include<vector>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn = 100005;
const int  INF = 9999999;
int n,m;
vector<int>G[maxn];
int pa[maxn][25];
int dist[maxn];
int deep[maxn];
int  vis[maxn];
//--------------------LCA---------------------------
//倍增法LAC 求最近公共祖先
void dfs(int pos,int d){
    deep[pos] = d;
    int Size = G[pos].size();
    for(int i = 0; i < Size; i++)
        dfs(G[pos][i],d + 1);
}
void lca_init(){
    for(int j = 1; j <= 20; j++)
        for(int i = 1; i <= n; i++)
            if(pa[i][j - 1] != -1)
                pa[i][j] = pa[pa[i][j - 1]][j - 1];
}
int lca(int a,int b){
    int j;
    if(deep[a] < deep[b]) swap(a,b);
    //讲AB置于同一深度
    for(int j = 20; j >= 0; j--){
        if(pa[a][j] != -1 && deep[pa[a][j]] >= deep[b])
            a = pa[a][j];
    }
    //
    if(a == b) return b;
    //倍增法
    for(int j = 20; j >= 0; j--){
        if(pa[a][j] != -1 && pa[a][j] != pa[b][j]){
            a = pa[a][j];
            b = pa[b][j];
        }
    }
    return pa[a][0];
}
//--------------------------------------------------
void bfs(){
    queue<int>q;
    int have[maxn] = {0};
    for(int i = 1; i <= n; i++)
        if(vis[i]){             //如果染色
            q.push(i);
            have[i] = 1;
            dist[i] = 0;
        }
    while(!q.empty()){
        int now = q.front(); q.pop();
        int Size = G[now].size();
        for(int i = 0; i < Size; i++)if(!have[G[now][i]]){
            have[G[now][i]] = 1;
            dist[G[now][i]] = dist[now] + 1;
            q.push(G[now][i]);
        }
        if(pa[now][0] != -1 && !have[pa[now][0]]){
            have[pa[now][0]] = 1;
            dist[pa[now][0]] = dist[now] + 1;
            q.push(pa[now][0]);
        }
    }
}
//--------------------------------------------------
vector<int>vv;
void init(){
    for(int i = 1; i <= n; i++) G[i].clear();
    vv.clear();
    memset(vis,-1,sizeof(vis));
    memset(pa,-1,sizeof(pa));
}
int main(){
    while(scanf("%d%d",&n,&m) != EOF){
        init();
        for(int i = 0; i < n - 1; i++){
            int x,y;
            scanf("%d%d",&x,&y);
            G[x].push_back(y);
            pa[y][0] = x;
            vis[y] = 0;
        }
        //找到根节点,并获得deep数组
        for(int i = 1; i <= n; i++)if(vis[i] == -1){
            pa[i][0] = -1;
            vis[i] = 0;
            vis[1] = 1;
            dfs(i,0);
            break;
        }
        lca_init();
        bfs();
        int calc = sqrt(m) + 1;
        for(int i = 0; i < m; i++){
            int op,v;
            scanf("%d%d",&op,&v);
            if(op == 1){
                vv.push_back(v);
                int S = vv.size();
                if(S == calc){
                    for(int i = 0; i < S; i++)
                        vis[vv[i]] = 1;
                    bfs();
                    vv.clear();
                }
            }
            else{
                int S = vv.size();
                int ans = dist[v];
                for(int i = 0; i < S; i++){
                    int c = lca(v,vv[i]);
                    int d = (deep[v] - deep[c]) + (deep[vv[i]] - deep[c]);
                    ans = min(ans,d);
                }
                printf("%d\n",ans);
            }
        }
    }
    return 0;
}

版权声明:本文为博主原创文章,未经博主允许不得转载。

【CodeForces】E. Xenia and Tree(分块 + LCA)

标签:

原文地址:http://blog.csdn.net/u013451221/article/details/47132707

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!