CodeForces 1228F One Node is Gone
洛谷题目页面传送门 & CodeForces题目页面传送门
给定一棵树\(T=(V,E),|V|=2^n-2,|E|=2^n-3\),输出所有的\(x\),使得存在一棵满二叉树\(T'\),将\(T'\)中节点\(x\)的一个儿子删除并把这个儿子的所有儿子接到\(x\)下后等于\(T\)。升序输出。
\(n\le17\)。
题目没有说以哪个点为根,也就是每个点都有可能是根,很自然地想到可以二次扫描与换根。先考虑选一个点作为根,那显然满足条件的改补的节点的父结点最多有\(1\)个。这个父结点可以DP出来。
我们将一个子树分类讨论:
是一棵满二叉树。设它的深度为\(d\),则记这颗子树的特征为有序对\((0,d)\)。这种情况发生当且仅当它有\(2\)棵子树并且都是矮\(1\)层的满二叉树。特殊地,如果它的大小为\(1\),则它的特征为\((0,1)\);
还原一个节点之后为满二叉树。设还原之后的深度为\(d\),补的节点的父结点为\(x\),则记这棵子树的特征为有序对\((x,d)\)。这种情况发生当且仅当以下任意一个条件为真:
- 它的根为\(x\),有\(1\)棵子树并且这棵子树大小为\(1\),此时应将改补的节点直接补在\(x\)下;
- 它的根为\(x\),有\(3\)棵子树并且其中\(1\)棵为矮\(1\)层的满二叉树,另\(2\)棵为矮\(2\)层的满二叉树,此时应将改补的节点补在\(x\)下并将\(2\)棵矮\(2\)层的字树接在改补的节点下;
- 它有\(2\)棵子树并且一棵为矮\(1\)层的满二叉树,另一颗补一个父结点为\(x\)的节点之后为矮\(1\)层的满二叉树;
不管补不补节点都不能成为满二叉树。记它的特征为有序对\((-1,-1)\)。显然,不满足\(1,2\)则为此种情况。
设\(dp_i\)为以\(1\)为根时以\(i\)为根的子树的特征,则状态转移方程是(太♂难写已隐藏)。这样一遍\(\mathrm O(2^n)\)DFS则可求出所有节点的DP值。而我们希望找到所有节点为根时的根节点DP值,这个可以二次扫描与换根,即再一遍DFS。每到达一个节点\(x\)时,目前所有节点的DP值均是以\(x\)为整棵树的根的,所以若\(dp_x=(y,n)(y>0)\),就将\(y\)加入答案序列。那么此时若要将它的某个儿子\(s\)改为根,那么改变的只有\(dp_x\)和\(dp_s\)。我们可以改一下它们的儿子集合(涉及添加和删除,用set
较为方便),重新算DP值,然后再DFS到\(s\),此时整棵树的根为\(s\)了。从\(s\)回溯时,再还原\(x\)和\(s\)的儿子集合和DP值,去找别的儿子即可。由于换根操作只需要改变\(2\)个节点的信息,所以复杂度是有保证的,一共\(\mathrm O(2^n\log2^n)=\mathrm O(2^nn)\)(\(\log\)是set
)。
下面贴代码:
#include<bits/stdc++.h>
using namespace std;
#define pb push_back
#define mp make_pair
#define X first
#define Y second
const int N=17;
int n;
vector<int> nei[1<<N];//邻接表
set<int> son[1<<N];//儿子集合
void dfs(int x=1,int fa=0){//求出所有节点的儿子集合
for(int i=0;i<nei[x].size();i++){
int y=nei[x][i];
if(y==fa)continue;
son[x].insert(y);
dfs(y,x);
}
}
pair<int,int> f[1<<N];//DP值,即以[1]为根的子树的特征
void calc_f(int x){//通过儿子集合计算DP值,即那个难写的状态转移方程
if(son[x].size()==0)f[x]=mp(0,1);
else if(son[x].size()==1)f[x]=f[*son[x].begin()]==mp(0,1)?mp(x,2):mp(-1,-1);
else if(son[x].size()==2){
pair<int,int> x1=f[*son[x].begin()],x2=f[*++son[x].begin()];
if(x1>x2)swap(x1,x2);
if(!x1.X&&!x2.X)f[x]=x1.Y==x2.Y?mp(0,x1.Y+1):mp(-1,-1);
else if(!x1.X&&x2.X>0)f[x]=x1.Y==x2.Y?mp(x2.X,x1.Y+1):mp(-1,-1);
else f[x]=mp(-1,-1);
}
else if(son[x].size()==3){
pair<int,int> x1=f[*son[x].begin()],x2=f[*++son[x].begin()],x3=f[*++ ++son[x].begin()];
if(x1>x2)swap(x1,x2);if(x2>x3)swap(x2,x3);if(x1>x2)swap(x1,x2);
if(!x1.X&&!x2.X&&!x3.X)f[x]=x1.Y==x2.Y&&x2.Y+1==x3.Y?mp(x,x3.Y+1):mp(-1,-1);
else f[x]=mp(-1,-1);
}
else f[x]=mp(-1,-1);
// printf("f[%d]=(%d,%d)\n",x,f[x].X,f[x].Y);
}
void dp(int x=1,int fa=0){//一遍DFS求出以1为整棵树的根时的DP数组
for(int i=0;i<nei[x].size();i++){
int y=nei[x][i];
if(y==fa)continue;
dp(y,x);
}
calc_f(x);
}
vector<int> ans;//答案序列
void dfs0(int x=1,int fa=0){//二次扫描
if(f[x].X>0)ans.pb(f[x].X);//加入答案序列
for(int i=0;i<nei[x].size();i++){
int y=nei[x][i];
if(y==fa)continue;
son[x].erase(y);son[y].insert(x);calc_f(x);calc_f(y);//改变儿子集合,重新算DP值
dfs0(y,x);
son[x].insert(y);son[y].erase(x);calc_f(y);calc_f(x);//还原
}
}
int main(){
cin>>n;
for(int i=1;i<=(1<<n)-3;i++){
int x,y;
cin>>x>>y;
nei[x].pb(y);nei[y].pb(x);
}
dfs();
dp();
dfs0();
cout<<ans.size()<<"\n";
sort(ans.begin(),ans.end());
for(int i=0;i<ans.size();i++)cout<<ans[i]<<" ";
return 0;
}
CodeForces 1228F One Node is Gone的更多相关文章
- babeljs源码
babel.min.js!function(e,t){"object"==typeof exports&&"object"==typeof mo ...
- node搜索codeforces 3A - Shortest path of the king
发一下牢骚和主题无关: 搜索,最短路都可以 每日一道理 人生是洁白的画纸,我们每个人就是手握各色笔的画师:人生也是一条看不到尽头的长路,我们每个人则是人生道路的远足者:人生还像是一块神奇的土地 ...
- CodeForces - 274B Zero Tree
http://codeforces.com/problemset/problem/274/B 题目大意: 给定你一颗树,每个点上有权值. 现在你每次取出这颗树的一颗子树(即点集和边集均是原图的子集的连 ...
- Codeforces 划水
Codeforces 566F 题目大意:给定$N$个数,任意两个数之间若存在一个数为另一个数的因数,那么这两个数存在边,求图中最大团. 分析:求一个图最大团为NP-Hard问题,一般不采用硬方法算. ...
- Codeforces Round #354 (Div. 2) ABCD
Codeforces Round #354 (Div. 2) Problems # Name A Nicholas and Permutation standard input/out ...
- CodeForces 548D 单调栈
Mike and Feet Time Limit:1000MS Memory Limit:262144KB 64bit IO Format:%I64d & %I64u Subm ...
- HDU 3333 | Codeforces 703D 树状数组、离散化
HDU 3333:http://acm.hdu.edu.cn/showproblem.php?pid=3333 这两个题是类似的,都是离线处理查询,对每次查询的区间的右端点进行排序.这里我们需要离散化 ...
- Codeforces VK CUP 2015 D. Closest Equals(线段树+扫描线)
题目链接:http://codeforces.com/contest/522/problem/D 题目大意: 给你一个长度为n的序列,然后有m次查询,每次查询输入一个区间[li,lj],对于每一个查 ...
- Codeforces Round #363 (Div. 2)
A题 http://codeforces.com/problemset/problem/699/A 非常的水,两个相向而行,且间距最小的点,搜一遍就是答案了. #include <cstdio& ...
随机推荐
- 性能测试基础---jmeter函数二次开发
Jmeter函数的二次开发. ·什么时候需要进行jmeter的自定义函数扩展呢? 一般来说,如果我们要对数据进行处理,而jmeter没有提供相应的功能(函数),此时我们可以自己进行自定义函数的扩展. ...
- 201871010132-张潇潇-《面向对象程序设计(java)》第四周学习总结
项目 内容 这个作业属于哪个课程 https://www.cnblogs.com/nwnu-daizh/ 这个作业的要求在哪里 https://www.cnblogs.com/nwnu-daizh/p ...
- destoon聚合搜索页面模板
最近学习大型站点SEO策略,谈到关于大站需要做聚合页面tags,所以根据destoon系统自己做了一个聚合页面,在此分享给吾爱的朋友,一起学习参考! 模板演示站点:http://zhimo.yuanz ...
- 洛谷P4549 裴蜀定理 / Min
原题链接 题目描述 给出n个数(A1...An)现求一组整数序列(X1...Xn)使得S=A1X1+...AnXn>0,且S的值最小 输入输出格式 输入格式: 第一行给出数字N,代表有N个数 下 ...
- dedecms手机站和PC站共用同一数据库的方法
我们知道搜索引擎建议将手机站和PC站分开,虽然自适应可以适配不同的终端,但单独建独立的m站可能权重和排名更好,因为移动端的竞争度不同甚至更低.代码更精简.蜘蛛抓取更顺畅,所以要单独建手机站比较好.那么 ...
- 架构篇 | 带你轻松玩转 LAMP 网站架构平台(一)
作者 | JackTian 微信公众号 | 杰哥的IT之旅(ID:Jake_Internet) 转载请联系授权(微信ID:Hc220066)备注:来自博客园 1.什么是 LAMP 架构? LAMP 架 ...
- 码云因为认证失败导致推送失败 生成 SSH 密钥对
- MapReduce 程序mysql JDBC驱动类找不到原因及学习hadoop写入数据到Mysql数据库的方法
报错 :ClassNotFoundException: com.mysql.jdbc.Driver 需求描述: hadoop需要动态加载个三方jar包(比如mysql JDBC 驱动包),是在MR结束 ...
- 【字符串】KMP
Algorithm Task 给定一个文本串 \(S\) 和一个模式串 \(T\),求 \(T\) 在 \(S\) 中出现的所有位置. Limitations 要求时空复杂度均为线性. Solutio ...
- Http状态码梳理汇总
常见的状态代码为:200 - 服务器成功返回网页404 - 请求的网页不存在503 - 服务器暂时不可用 1xx(临时响应) 用于表示临时响应并需要请求者执行操作才能继续的状态代码.代码 说明 100 ...