【树上启发式合并】 HDU6430

例题:给一棵n个节点的树,每个节点有一个颜色1<=c[i]<=n,q次查询颜色c在子树i上出现次数。

首先我们可以快速想到一种时间复杂度为O(n^2)的暴力做法。为啦和启发式合并相关,我们考虑这样的暴力算法。



void dfs(int x,int fa)
{
    for(int i=0;i

对于一个节点,我们定义其最大子树为重儿子,其它皆为轻儿子。然后,在更新时,如果每个节点都继承其重儿子的答案,就可以减少更新,然后就可以将时间复杂度降为为O(logn)。这个证明,容我想想。


void build(int x)
{
    sz[x]=1;
    st[x]=++top;
    be[top]=x;
    for(int i=0;isz[bc])bc=y;
    }
    for(int i=0;i


HDU 6430 

题意:给一棵n个节点的树,根节点为1,每个节点都有一个值val[i](val[i]<1e5)。然后求对于x,求这棵树上两点的LCA为x的所有数对中GCD最大为多少。

题解:由于val[i]很小,每个数约数很少,不超过200,然后只要数上启发式合并记录一下这个约数在这个子树上是否出现过,就可以求出答案。访问到一个节点,首先从重儿子那继承啦约数,由于要求LCA为根节点,只要比较重儿子和根,然后合并,然后依次和每一个轻儿子比较,就可以求出答案,维护过程可以用bitset维护。

#include
using namespace std;
const int N=1e5+1;
const int T=1e5;
int sz[N],st[N],ed[N],be[N],va[N],top=0,ans[N];
vector g[N],dv[N];
void build(int x)
{
    sz[x]=1;
    st[x]=++top;
    be[top]=x;
    for(int i=0;i btem,bt;
void dfs(int x,int op)
{


    int bc=0;
    for(int i=0;isz[bc])bc=y;
    }
    for(int i=0;i

 

你可能感兴趣的:(【图论】-大合集)