BZOJ 1086 [SCOI2005]王室联邦 树分块
2015-08-05 15:25
375 查看
题意:链接
方法:树分块
解析:
为了去刷莫队上树所以来学习树分块,听说这是裸题所以跑来搞。
树分块的过程是什么?
从树根向下递归搜索,如果回溯的节点超过了我们想分成的块的大小(不妨设为a),就将这些节点作为一个块,并且回溯到的这个节点是与该块中的任意节点连通的。
这里显然可以用一个栈来处理。
并且需要注意的是,如果我们不加以限制,会出现什么结果呢?会使分的块中的元素碎成渣,即瞎分。
什么限制呢?
是对于每个节点的相对栈底的限制。
如果在当前节点,其有两个儿子。
在左儿子的子树中搜得的节点数是a-1的话,这时候我们去搜右儿子,不妨假设右儿子为根的子树是一条长为10000的链。
那么显然最下面的叶节点跟左儿子代表的子树是在同一块中的,这显然碎成渣了。
所以每一次搜到一个节点,我们都要把当前的栈的指针当做该节点的相对栈底,这样的话就能避免这个问题。
如上内容请自行脑补。
这样就完了吗?
并没有。
最后的栈中还会剩很多点,但是不会超过b,而我们分的块的大小也不会超过2b(自行脑补),所以把栈里的所有点扔到最后一块里,大小不会超过3b,正好对应题中的要求。
代码:
#include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #define N 1010 using namespace std; int sta ; int n,b,cnt; int head ; int root ; int belong ; bool v ; int tot,top; struct node { int from,to,next; }edge[N<<1]; void init() { memset(head,-1,sizeof(head)); cnt=1; } void edgeadd(int from,int to) { edge[cnt].to=to; edge[cnt].next=head[from]; head[from]=cnt++; } void dfs(int now) { v[now]=1; int bot=top; for(int i=head[now];i!=-1;i=edge[i].next) { int to=edge[i].to; if(v[to])continue; dfs(to); if(top-bot>=b) { tot++; root[tot]=now; do { belong[sta[top]]=tot; top--; }while(top!=bot); } } sta[++top]=now; } int main() { init(); scanf("%d%d",&n,&b); for(int i=1;i<n;i++) { int x,y; scanf("%d%d",&x,&y); edgeadd(x,y); edgeadd(y,x); } dfs(1); while(top) { belong[sta[top--]]=tot; } cout<<tot<<endl; for(int i=1;i<n;i++)cout<<belong[i]<<' '; cout<<belong <<endl; for(int i=1;i<tot;i++)cout<<root[i]<<' '; cout<<root[tot]<<endl; }
相关文章推荐
- system verilog中的跳转操作
- 开学季,送给新生入学的礼物‘校园网络TV’
- 进制转换
- Linux设备驱动核心理论(二)
- Balanced Binary Tree
- hdu 1010 Tempter of the Bone
- c++技术系统学习资料
- Alamofire 网络访问框架使用
- 浅析Java设计模式之适配器模式
- Docker点滴
- SAR 命令详解
- Calendar Game(找规律+博弈)
- javascript的一些小知识1
- LayoutParams的用法,及LayoutInflater区别
- 关于cocos2d-x3.0和2.0之间的区别
- JSP中文乱码问题终极解决方案
- 为什么父进程不处理标准输入输出子进程会挂起(Java)?
- struts.xml 中配置常量constant详解
- 回归、插值、逼近、拟合的区别
- Android开发---音乐播放器(Activity实现)