树上的有些问题是可以用树剖或者动态树解决的,但是他们有一个动同点就是:不连通。

  • 比如求u到v的路径权值和,或者最大值:

                u到v可能对应了多个链,这多个链在对应的数据结构(假设是线段树)上面对应不同的区间。但是线段树上这几个区间的不连续并不影响我们得到答案。

                (当然求子树的信息话是连续区间)

那么如果我们遇到的问题要求区间连续呢,比如求u到v的路径上点的权值有多少种?如果不连续就得处理链与链之间的关系。显然这些点得待在一起,如果树剖很难维护链与链之间的关系。

树分块,大概有这样的一些方法: 

  • 王室联邦分块法:可以保证每个块的大小和直径都不超过1,但是不保证块联通 
  • ,但是不保证直径,也不保证联通。处理子树信息比较方便 
  • √N,保证块内联通,还保证直径,多么优美啊可惜不能保证块个数(一个菊花图就死了)

 

王室联邦分块,假设每个块的数量个数为[B,3B].

     如何分组可以看,裸题 BZOJ1086 王室联邦。 

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
int const maxn=2010;
int q[maxn],group[maxn],rt[maxn],top;
int Laxt[maxn],Next[maxn],To[maxn],cnt,ans;
int n,B;
void init()
{
    ans=0;  top=0;  cnt=0; 
    memset(Laxt,0,sizeof(Laxt));
}
void add(int u,int v)
{
    Next[++cnt]=Laxt[u];
    Laxt[u]=cnt;
    To[cnt]=v;
}
void dfs(int u,int pre)
{
    int Now=top;
    for(int i=Laxt[u];i;i=Next[i]){
        if(To[i]!=pre){
           dfs(To[i],u);
           if(top-Now>=B) { rt[++ans]=u; while(top!=Now) group[q[top--]]=ans;}
        }
    } q[++top]=u;
}
int main()
{
    while(~scanf("%d%d",&n,&B)){
        int u,v; init();
        for(int i=1;i<n;i++){
            scanf("%d%d",&u,&v);
            add(u,v);add(v,u);
        }   dfs(1,0);
        while(top) group[q[top--]]=ans;  printf("%d\n",ans);
        for(int i=1;i<=n;i++) printf("%d ",group[i]);printf("\n");
        for(int i=1;i<=ans;i++) printf("%d ",rt[i]);printf("\n");
    } return 0;
}
View Code

相关文章:

  • 2021-12-28
  • 2021-12-03
  • 2021-06-27
  • 2021-10-10
  • 2021-11-18
  • 2021-06-05
  • 2021-11-18
  • 2022-01-04
猜你喜欢
  • 2022-12-23
  • 2021-07-15
  • 2022-02-08
  • 2021-06-20
  • 2022-12-23
相关资源
相似解决方案