HDU5764 After a Sleepless Night 树形乱搞题
分析(官方题解):
假设根已确定,可以发现新树若合法,需满足以下性质:根节点是n;儿子的值不大于父亲;具有相同值的节点形成一条链,并且链不会发生“分叉”(即有多个最低点)。所以对于新树中有出现的值x,原树在新树x链的最低点应为x,而其他新值为x的点,原值应小于x。那么我们先将所有链的最低点放上对应值,而空着的点和还没用的值进行配对。 贪心使答案字典序最小:从大到小枚举未用的值,用大根堆维护该值可以填入的位置id,取最大id填入。(否则,若某一步的值a匹配了非最大id x,而最大id y在后面配了值b,那么交换xy将产生更优解)。 还有一种方法是从大到小枚举空位置,填入 最接近小于 该位置新值的 未用的值。这用set是容易实现的。并且队友想出了使用并查集+双向链表的写法,可做到并查集复杂度(O(n*a(n)))。 不合法的情况除了不满足上述性质,还有就是匹配的过程中出现值或位置不够用。
然后考虑根的选择。由上所述,根的值一定是新树n链的两个端点之一。可以发现,无论选哪个做根,不影响其它链的上下方向及链之间的相对关系,即不影响合法性。因为没选的那一头一定填n,所以我们贪心地选择id小的端点做根(否则交换两个端点的值,将得到更优的答案)。当然也可以两个点都跑一遍。 (出题人写hint的时候,把自己绕晕了。不好意思。)
一点感想:这个题就是说原树是有根树(每个点有权值),新树每个节点的权值是其子树的最大值
由于是排列(也就是每个权值都不一样),所以只有链状,具体的分析见这一篇
http://blog.csdn.net/bblss123/article/details/52058959
#include <cstdio>
#include <cstring>
#include <vector>
#include <queue>
#include <algorithm>
using namespace std;
typedef long long LL;
const int N = 1e5+;
int head[N],tot;
struct Edge{
int v,next;
}edge[N<<];
void add(int u,int v){
edge[tot].v=v;
edge[tot].next=head[u];
head[u]=tot++;
}
int val[N],ret[N],d[N],n,T,color[N],fa[N],kase;
vector<int>s;
bool can[N];
bool dfs(int u){
int sp=;
for(int i=head[u];~i;i=edge[i].next){
int v=edge[i].v;
if(v==fa[u])continue;
if(val[v]>val[u])return false;
else if(val[v]==val[u]){if((++sp)>)return false;}
fa[v]=u;
if(!dfs(v))return false;
}
if(!sp){color[val[u]]=u;ret[u]=val[u];can[val[u]]=false;}
return true;
}
bool solve(){
s.clear();scanf("%d",&n);tot=;
for(int i=;i<=n;++i)color[i]=head[i]=-,fa[i]=d[i]=,can[i]=true;
for(int i=;i<=n;++i){
scanf("%d",&val[i]);
if(val[i]==n)s.push_back(i);
}
for(int i=;i<n;++i){
int u,v;scanf("%d%d",&u,&v);
add(u,v);add(v,u);
if(val[u]==n&&val[v]==n)++d[u],++d[v];
}
if(!s.size())return false;
for(int i=;i<s.size();++i)
if(d[s[i]]<d[s[]]||d[s[i]]==d[s[]]&&s[i]<s[])
swap(s[i],s[]);
if(d[s[]]>)return false;
if(!dfs(s[]))return false;
priority_queue<int>q;
for(int i=n;i>;--i){
if(can[i]){
if(q.empty())return false;
ret[q.top()]=i;q.pop();
}
if(color[i]!=-){
int tmp=color[i];
while(val[fa[tmp]]==i){
q.push(fa[tmp]);
tmp=fa[tmp];
}
}
}
return true;
}
int main(){
scanf("%d",&T);
while(T--){
printf("Case #%d:",++kase);
if(!solve())printf(" Impossible\n");
else {
for(int i=;i<=n;++i)printf(" %d",ret[i]);
printf("\n");
}
}
return ;
}
HDU5764 After a Sleepless Night 树形乱搞题的更多相关文章
- CF_402C Searching for Graph 乱搞题
题目链接:http://codeforces.com/problemset/problem/402/C /**算法分析: 乱搞题,不明白题目想考什么 */ #include<bits/stdc+ ...
- codeforces 653C C. Bear and Up-Down(乱搞题)
题目链接: C. Bear and Up-Down time limit per test 2 seconds memory limit per test 256 megabytes input st ...
- codeforces 664B B. Rebus(乱搞题)
题目链接: B. Rebus time limit per test 1 second memory limit per test 256 megabytes input standard input ...
- codeforces 669D D. Little Artem and Dance(乱搞题)
题目链接: D. Little Artem and Dance time limit per test 2 seconds memory limit per test 256 megabytes in ...
- hihocoder 1236(2015北京网络赛 J题) 分块bitset乱搞题
题目大意: 每个人有五门课成绩,初始给定一部分学生的成绩,然后每次询问给出一个学生的成绩,希望知道在给定的一堆学生的成绩比这个学生每门都低或者相等的人数 因为强行要求在线查询,所以题目要求,每次当前给 ...
- AOJ.176 两数组最短距离 (乱搞题)
两数组最短距离 点我挑战题目 题意分析 给出2个数组,让求出2个数组元素差的绝对值的最小值是多少. 我这里是o(m+n)的算法.首先对于第一个数组,让他的第一个元素和第二个元素比较,如果他的第一个元素 ...
- hdu 4112 Break the Chocolate(乱搞题)
题意:要把一块n*m*k的巧克力分成1*1*1的单元,有两种操作方式:1,用手掰(假设力量无穷大),每次拿起一块,掰成两块小的:2,用刀切(假设刀无限长),可以把多块摆在一起,同时切开.问两种方式各需 ...
- AT2386 Colorful Hats (乱搞题,思维题)
分情况讨论的神题... max不等于min + 1 或者不等于min,这种情况显然不存在. 如果都等于一个数 有两种情况: 互相独立,那么a[i]肯定==n-1 有相同的,那么a[i]一定不是独立的. ...
- hdu-5676 ztr loves lucky numbers(乱搞题)
题目链接: ztr loves lucky numbers Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/65536 K ( ...
随机推荐
- hdu2018
http://acm.hdu.edu.cn/showproblem.php?pid=2018 #include<iostream> #include<stdio.h> #inc ...
- Tomcat7.0 start Could not find the main class: org.apache.catalina.startup.Bootstrap.
java.lang.NoClassDefFoundError: org/apache/juli/logging/LogFactory at org.apache.catalina.startup.Bo ...
- 2014-9-17二班----11 web project
http://localhost:8080/rwkj1/indexServlet?name=zhagnsan&pwd=1234 跳 转 http://localhost:8080/rwkj ...
- SqlServer 如何以脚本形式导出数据
你是否遇到这样的情况,在公司导出一个数据库,回到家里导入自己的电脑里,然后发现数据库版本不匹配,这真是一个悲剧. 那么以下这个方法就可以避免这个悲剧,将数据以脚本的形式导出,这样灵活性更好. 1.选择 ...
- C#实现Comparable接口实现排序
C#中,实现排序的方法有两种,即实现Comparable或Comparer接口,下面简单介绍实现Comparable接口实现排序功能. 实现Comparable接口需要实现CompareTo(obje ...
- Support Library官方教程(3)android studio中导入支援包
Support Library Setup How you setup the Android Support Libraries in your development project depend ...
- Bug:java.lang.IllegalStateException
使用迭代的时候,出现了java.lang.IllegalStateException 代码: for ( TaskInfo info : userTaskInfos ) { if ( info.isC ...
- 对mysql经常使用语句的详细总结
下面总结的知识点全是经常用的,全都是干货,好好收藏吧. /* 启动mysql */net start mysql /* 连接与断开服务器 */mysql -h 地址 -p 端口 -u 用户名 -p 密 ...
- poj 1195 Mobile phones(二维树状数组)
树状数组支持两种操作: Add(x, d)操作: 让a[x]增加d. Query(L,R): 计算 a[L]+a[L+1]……a[R]. 当要频繁的对数组元素进行修改,同时又要频繁的查询数组内任一 ...
- WebActivatorEx
using System; using NLog; using System.Web.Optimization; [assembly: WebActivatorEx.PreApplicationSta ...