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

对于两个操作,对于操作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;
}

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

时间: 2024-10-15 08:44:06

【CodeForces】E. Xenia and Tree(分块 + LCA)的相关文章

Codeforces 461B Appleman and Tree(木dp)

题目链接:Codeforces 461B Appleman and Tree 题目大意:一棵树,以0节点为根节点,给定每一个节点的父亲节点,以及每一个点的颜色(0表示白色,1表示黑色),切断这棵树的k条边,使得树变成k+1个联通分量.保证每一个联通分量有且仅有1个黑色节点.问有多少种切割方法. 解题思路:树形dp,dp[i][0]和dp[i][1]分别表示子树一下的切割方法中,i节点所在联通块不存在黑节点和已经存在一个黑节点的方案数. #include <cstdio> #include &l

codeforces 161D - Distance in Tree(树形dp)

题目大意: 求出树上距离为k的点对有多少个. 思路分析: dp[i][j] 表示 i 的子树中和 i 的距离为 j 的点数有多少个.注意dp[i] [0] 永远是1的. 然后在处理完一颗子树后,就把自身的dp 更新. 更新之前更新答案. 如果这颗子树到 i 有 x 个距离为j的.那么答案就要加上 dp[i] [ k-j-1] * x; #include <iostream> #include <cstdio> #include <cstring> #include &l

Codeforces 461B Appleman and Tree(树形dp)

题目链接:Codeforces 461B Appleman and Tree 题目大意:一棵树,以0节点为根节点,给定每个节点的父亲节点,以及每个点的颜色(0表示白色,1表示黑色),切断这棵树的k条边,使得树变成k+1个联通分量,保证每个联通分量有且仅有1个黑色节点.问有多少种分割方法. 解题思路:树形dp,dp[i][0]和dp[i][1]分别表示子树一下的分割方法中,i节点所在联通块不存在黑节点和已经存在一个黑节点的方案数. #include <cstdio> #include <c

Educational Codeforces Round 25 G. Tree Queries

题目链接:Educational Codeforces Round 25 G. Tree Queries 题意: 给你一棵树,一开始所有的点全是黑色,有两种操作. 1 x 将x这个点变为黑色,保证第一个操作是这个. 2 x 询问x到任意黑色的点的简单路径上的最小节点编号. 题解: 首先将一个变为黑色的点当成树根,然后dfs一下,预处理出所有点的答案. 然后开一个变量记录一下当前变黑的点的答案cur=min(cur,dp[x]). 每次询问的时候答案就是min(cur,dp[x]). 如果觉得很神

Codeforces.280C.Game on Tree(期望)

题目链接 参考:浅谈期望的线性性(可加性) Codeforces 280C Game on Tree 概率dp 树上随机删子树 求删完次数的期望(这个的前半部分分析并没有看..) \(Description\) 给你一棵有\(n\)个白点的有根树,每次随机选择一个点,将它和它的子树中所有点染黑. 问期望操作多少次后所有点都被染黑? \(Solution\) 期望好玄啊..(好吧是我太弱) 因为概率具有可加性,一棵树可以分解为多棵子树,而子树分解的最终状态就是点,所以我们可以计算每个点的期望操作次

codeforces 342E :Xenia and Tree

Description Xenia the programmer has a tree consisting of n nodes. We will consider the tree nodes indexed from 1 to n. We will also consider the first node to be initially painted red, and the other nodes — to be painted blue. The distance between t

CodeForces 593D Happy Tree Party [LCA+并查集]

题意:给一棵树,每条边有一个权值,给两种操作,第一种是询问y向下整除从a到b的最短路径中每条边的权值后y的值,第二种是改变某条边的权值. 思路:y的最大值为1e18,最多除大于等于2的数不超过60次即可将y变为0,先dfs以任意一点为根建树,记录每个点的深度和它的父结点并将边权转化为点权, 再搞个并查集,将权值为1的点压缩,即使pre[u]=g[u];(u变成u的爸爸). 1 #include<bits/stdc++.h> 2 #define fi first 3 #define se sec

codeforces 551E. GukiZ and GukiZiana 分块

题目链接 给出n个数, m个操作, 每个操作有两种, 将一段区间加上某个值, 或者询问一个k, a[i] = a[j] = k, 输出满足条件的最大的j-i, 如果没有输出-1. 做法是将数组分块, 第一次做这种, 抄的codeforces上面的代码... #include<bits/stdc++.h> using namespace std; #define pb(x) push_back(x) #define ll long long #define mk(x, y) make_pair(

CodeForces 396C On Changing Tree

On Changing Tree Time Limit: 2000ms Memory Limit: 262144KB This problem will be judged on CodeForces. Original ID: 396C64-bit integer IO format: %I64d      Java class name: (Any) You are given a rooted tree consisting of n vertices numbered from 1 to