倍增法求lca:暗的连锁

https://loj.ac/problem/10131

#include<bits/stdc++.h>
using namespace std;
struct node{
    int to,next;
}e[1000001];
int head[500000],num=0,N,n,m,ans;
int grand[500001][20],depth[500001];
int f[100000],w[1000000];
inline void add(int x,int y)
{
    e[++num].to=y,e[num].next=head[x],head[x]=num;
}
inline void read(int &x)
{
    x=0;int f=1;
    char s=getchar();
    while(s<‘0‘||s>‘9‘){if(s==‘-‘)f=-1;s=getchar();}
    while(s>=‘0‘&&s<=‘9‘){x=x*10+s-‘0‘;s=getchar();}
    x*=f;
}
void dfs(int x)
{
    for(int i=1;i<=N;i++)grand[x][i]=grand[grand[x][i-1]][i-1];
    for(int i=head[x];i;i=e[i].next)
    {
        int v=e[i].to;
        if(v==grand[x][0])continue;
        depth[v]=depth[x]+1;
        grand[v][0]=x;
        dfs(v);
    }
}
void init()
{
    N=floor(log(n+0.0)/log(2.0));
    depth[1]=1;
    dfs(1);
}
inline int lca(int a,int b)
{
    if(depth[a]>depth[b]) swap(a,b);
    for(register int i=N;i>=0;i--)
    {
        if(depth[a]<depth[b]&&depth[grand[b][i]]>=depth[a]) b=grand[b][i];
    }
    if(a==b)return a;
    for(register int i=N;i>=0;i--)
    {
        if(grand[a][i]!=grand[b][i]){a=grand[a][i],b=grand[b][i];}
    }
    return grand[a][0];
}
void solve(int u,int fa)
{
    for(int i=head[u];i;i=e[i].next)
    {
        int v=e[i].to;if(v==fa) continue;
        solve(v,u);f[u]+=f[v];
    }
}
int main()
{
    read(n),read(m);
    for(int i=1;i<n;i++)
    {
        int u,v;
        read(u),read(v);
        add(u,v);
        add(v,u);
    }
    init();
    for(int i=1;i<=m;i++)
    {
        int x,y;
        read(x),read(y);
        w[x]++;w[y]++;
        w[lca(x,y)]-=2;
    }
    for(int i=1;i<=n;i++) f[i]=w[i];
    solve(1,0);
    for(int i=2;i<=n;i++)
    {
        if(f[i]==0) ans+=m;
        else if(f[i]==1) ans++;
    }
    cout<<ans;
}

原文地址:https://www.cnblogs.com/719666a/p/9573244.html

时间: 2024-10-18 11:48:01

倍增法求lca:暗的连锁的相关文章

poj1330Nearest Common Ancestors以及讲解倍增法求lca

Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 20487   Accepted: 10784 Description A rooted tree is a well-known data structure in computer science and engineering. An example is shown below: In the figure, each node is labeled with an

倍增法求LCA

倍增法求LCA LCA(Least Common Ancestors)的意思是最近公共祖先,即在一棵树中,找出两节点最近的公共祖先. 倍增法是通过一个数组来实现直接找到一个节点的某个祖先,这样我们就可以在O(logn)的时间内求出求出任意节点的任意祖先. 然后先把两个节点中转化为深度相同的节点,然后一起向上递增,知道找到相同的节点,该节点就是这两个节点的最近公共祖先. 代码实现: 1 #include<cstdio> 2 #include<iostream> 3 #define N

用“倍增法”求最近公共祖先(LCA)

1.最近公共祖先:对于有根树T的两个结点u.v,最近公共祖先LCA(T,u,v)表示一个结点x,满足x是u.v的祖先且x的深度尽可能大.2.朴素算法:记录下每个节点的父亲,使节点u,v一步一步地向上找父亲,直到找到相同的“祖先”,即 是所求的答案,时间复杂度O(n).3.优化算法(倍增法):利用二进制的思想,想办法使一步一步向上搜变成以2^k地向上跳. 所以定义一个P[][]数组,使p[i][j]表示节点i的2^j倍祖先,因此p[i][0]即为i的父亲. 我们可以得到一个递推式p[i][j]=p

SPOJ COT2 Count on a tree II (树上莫队,倍增算法求LCA)

题意:给一个树图,每个点的点权(比如颜色编号),m个询问,每个询问是一个区间[a,b],图中两点之间唯一路径上有多少个不同点权(即多少种颜色).n<40000,m<100000. 思路:无意中看到树上莫队,只是拿来练练,没有想到这题的难点不在于树上莫队,而是判断LCA是否在两点之间的路径上的问题.耗时1天. 树上莫队的搞法就是: (1)DFS一次,对树进行分块,分成sqrt(n)块,每个点属于一个块.并记录每个点的DFS序. (2)将m个询问区间用所属块号作为第一关键字,DFS序作为第二关键字

LCA 在线倍增法 求最近公共祖先

第一步:建树  这个就不说了 第二部:分为两步  分别是深度预处理和祖先DP预处理 DP预处理: int i,j; for(j=1;(1<<j)<n;j++) for(int i=0;i<n;++i) if(fa[i][j]=-1) fa[i][j]=fa[fa[i][j-1]][j-1];/*DP处理出i的2^j祖先是谁*/ 深度预处理: 1 void dfs(int now,int from,int deepth) 2 { 3 deep[now]=deepth; 4 for(i

Misha, Grisha and Underground CodeForces - 832D (倍增树上求LCA)

Misha and Grisha are funny boys, so they like to use new underground. The underground has n stations connected with n - 1 routes so that each route connects two stations, and it is possible to reach every station from any other. The boys decided to h

HDU 5296 Annoying Problem 树链剖分 LCA 倍增法

HDU 5296 Annoying Problem 题目链接:hdu 5296 题意:在一棵给定的具有边权的树,一个节点的集合S(初始为空),给定Q个操作,每个操作增加或删除S中的一个点,每个操作之后输出使集合S中所有点联通的最小子树的边权和. 思路:最小子树上的节点的充要条件: 节点为(S集合中所有点的LCA)的子节点: 节点有一个子孙为S集合中的点. 那么我们给每个节点都开一个标记数组,初始为零,每加入一个节点,就把从这个节点到根节点路径上的点的值都+1,反之-1,这样通过对每个单节点值的查

POJ 1986:Distance Queries(倍增求LCA)

http://poj.org/problem?id=1986 题意:给出一棵n个点m条边的树,还有q个询问,求树上两点的距离. 思路:这次学了一下倍增算法求LCA.模板. dp[i][j]代表第i个点的第2^j个祖先是哪个点,dp[i][0] = i的第一个祖先 = fa[i].转移方程:dp[i][j] = dp[dp[i][j-1][j-1]. 1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm&g

求 LCA 的三种方法

(YYL: LCA 有三种求法, 你们都知道么?) (众神犇: 这哪里来的傻叉...) 1. 树上倍增 对于求 LCA, 最朴素的方法是"让两个点一起往上爬, 直到相遇", "如果一开始不在同一深度, 先爬到同一深度". 树上倍增求 LCA 的方法同样基于这个道理, 只不过利用了倍增思想从而加速了"向上爬"的操作. 也就是说, 每次向上爬的高度不是 1, 而是 2 的幂. 我们用 $f(i, j)$ 表示从节点 $i$ 向上爬 $2^j$ 的高度