tkdsheep-solution-0015

从 Trac 迁移的文章

这是从旧校内 Wiki 迁移的文章,可能存在一些样式问题,您可以向 memset0 反馈。

原文章内容如下:

{{{
给一棵n个点的树,以及C种颜色,要在树上给每个点染色,并且直接相连的两个点不能有相同颜色
然后现在有很多次查询,每次查询问的是如果在树上再加一条边,染色方案数会减少多少

一步一步分析这个问题,首先如果只是一条链上的n个点,首先随便选一个初始点,它有C种颜色可以染
然后其他点就只有C-1种颜色可用了,所以答案是C*(C-1)^n-1

树上的情况其实和链是一样的,自己想一下就明白了,因为一个点最多之和两个点相连

现在在树上加一条边,实际就变成来一个“章鱼树”,即中间一个环,环上的某些点延伸出很多棵子树
设总共有n个点,环上的点有m个,f[m]表示m个点构成的环有多少种染色方案
则剩下的n-m个点(章鱼腿上的点)每个点都有C-1种颜色可选,所以答案就是f[m]*(C-1)^n-m

那么如何快速求出加边之后,得到的环有多少个点?设加进去的边的两个端点是u和v
则环上点的个数为 d[u]+d[v]-2*d[lca(u,v)]+1
数组d表示节点的深度(到根节点的距离),其中d[root]=1,lca则为u和v的最近公共祖先

所以可以在logn的时间求出环上点的个数

那么f[i]怎么计算呢?

f[i] = f[i-1]*(C-2)+f[i-2]*(C-1) (i>=4)

为什么是这样推的?自己画一下就知道了。。。跟错排公式的推法有点类似吧

}}}



{{{
附:

LCA离线tarjan伪代码

//parent为并查集,FIND为并查集的查找操作

//QUERY为询问结点对集合

//TREE为基图有根树 

Tarjan(u)      

    visit[u] = true   

    for each (u, v) in QUERY     

        if visit[v]    

        ans(u, v) = FIND(v)   

    for each (u, v) in TREE    

        if !visit[v]        

            Tarjan(v)   

            parent[v] = u

}}}
给一棵n个点的树,以及C种颜色,要在树上给每个点染色,并且直接相连的两个点不能有相同颜色
然后现在有很多次查询,每次查询问的是如果在树上再加一条边,染色方案数会减少多少
一步一步分析这个问题,首先如果只是一条链上的n个点,首先随便选一个初始点,它有C种颜色可以染
然后其他点就只有C-1种颜色可用了,所以答案是C*(C-1)^n-1
树上的情况其实和链是一样的,自己想一下就明白了,因为一个点最多之和两个点相连
现在在树上加一条边,实际就变成来一个“章鱼树”,即中间一个环,环上的某些点延伸出很多棵子树
设总共有n个点,环上的点有m个,f[m]表示m个点构成的环有多少种染色方案
则剩下的n-m个点(章鱼腿上的点)每个点都有C-1种颜色可选,所以答案就是f[m]*(C-1)^n-m
那么如何快速求出加边之后,得到的环有多少个点?设加进去的边的两个端点是u和v
则环上点的个数为 d[u]+d[v]-2*d[lca(u,v)]+1
数组d表示节点的深度(到根节点的距离),其中d[root]=1,lca则为u和v的最近公共祖先
所以可以在logn的时间求出环上点的个数
那么f[i]怎么计算呢?
f[i] = f[i-1]*(C-2)+f[i-2]*(C-1) (i>=4)
为什么是这样推的?自己画一下就知道了。。。跟错排公式的推法有点类似吧
附:
LCA离线tarjan伪代码
//parent为并查集,FIND为并查集的查找操作
//QUERY为询问结点对集合
//TREE为基图有根树 
Tarjan(u)      
    visit[u] = true   
    for each (u, v) in QUERY     
        if visit[v]    
        ans(u, v) = FIND(v)   
    for each (u, v) in TREE    
        if !visit[v]        
            Tarjan(v)   
            parent[v] = u