拿来学了一下树分块。
树分块的要求是把树分成⌈NB⌉块,每一块的每个节点到这个块的lca的之间的节点数不超过3B.
(好像在很久以前听谁讲过。。)做法是按dfs序出栈或bfs倒序考虑,把当前这个子树的剩余块加到它的父亲上,如果它的父亲上的块已经≥b就把这个块取出来。这样的话出来的就是若干大小在[b,2b)的块加上一个在[0,b)的块,注意到按dfs或bfs序考虑时,倒数第二个块与最后一个块一定是联通的,所以可以把它们俩并起来,这样大小就在[0,3b)了。
#include<cstdio>
#include<iostream>
using namespace std;
#include<algorithm>
#include<vector>
const int N=1000+5,B=1000+5;
int next[N<<1],succ[N<<1],ptr[N],etot=1;
void addedge(int from,int to){
next[etot]=ptr[from],ptr[from]=etot,succ[etot++]=to;
}
int capital[N],bnum[N],btot=1;
int size[N];
int fa[N];
vector<int> son[N];
int treeq[N],blockq[N];
int main(){
freopen("bzoj_1086.in","r",stdin);
int n,b;
scanf("%d%d",&n,&b);
int u,v;
for(int i=n;--i;){
scanf("%d%d",&u,&v);
addedge(u,v),addedge(v,u);
}
treeq[0]=1;
for(int h=0,t=1;h!=t;++h)
for(int i=ptr[treeq[h]];i;i=next[i])
if(succ[i]!=fa[treeq[h]]){
fa[succ[i]]=treeq[h];
treeq[t++]=succ[i];
}
for(int h=n;h--;){
size[fa[treeq[h]]]+=size[treeq[h]]+1;
son[fa[treeq[h]]].push_back(treeq[h]);
if(size[fa[treeq[h]]]>=b){
blockq[0]=fa[treeq[h]];
for(int h=0,t=1;h!=t;++h)
for(int i=son[blockq[h]].size();i--;){
bnum[son[blockq[h]][i]]=btot;
blockq[t++]=son[blockq[h]][i];
}
//printf("capital(%d)=%d\n",btot,fa[treeq[h]]);
capital[btot++]=max(fa[treeq[h]],1);
size[fa[treeq[h]]]=0;
son[fa[treeq[h]]].clear();
}
}
blockq[0]=0;
--btot;
for(int h=0,t=1;h!=t;++h)
for(int i=son[blockq[h]].size();i--;){
bnum[son[blockq[h]][i]]=btot;
blockq[t++]=son[blockq[h]][i];
}
printf("%d\n",btot);
for(int i=1;i<n;++i)printf("%d ",bnum[i]);
printf("%d\n",bnum[n]);
for(int i=1;i<btot;++i)printf("%d ",capital[i]);
printf("%d\n",capital[btot]);
}