51Nod 1558 树中的配对
题目链接
分析:
想了好久~~~还是得看题解...QwQ
首先因为是排列,所以我们猜想要把式子拆开来看, $ \sum dis(i,p[i])=\sum dep[i]+dep[p[i]]-2*dep[lca[i,p[i]]] $ ,定义 $ dep[i] $ 代表 $ i $ 到根节点的距离...
也就是说,其实我们只需要最小化$\sum dep[lca[i],p[i]]$...
我们如果考虑贪心的思想,那么显然$i$和$p[i]$不在一棵子树中的时候$lca$为$root$,那么$dep[lca]$为$0$,所以考虑能否找到一个合法的根节点,使得点两两配对并且不在一个子树中...
显然是可以的,这个优秀的根节点就是重心...
考虑重心的性质,去掉重心之后,每棵子树的大小都不会超多$\frac {n}{2}$,所以说一定存在合法的解...
那么考虑如何解决字典序最小的问题...
如果$u$和$v$匹配,但是$v$不一定和$u$匹配,所以我们把每个点拆成两个点,一个代表下标,一个代表排列,如果我们要找当前点匹配点,那么我们就去找到最大的子树,判断$size$是否刚好为当前点数的一半,如果是,那么我们就必须在这棵子树中找答案,否则就在非$u$的子树中找答案,然后在$u$的子树中删去$u$的下标点,在答案的子树中删去答案的排列点,然后用线段树维护子树内的标号最小值...
代码:
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<set>
//by NeighThorn
#define inf 0x3f3f3f3f
#define Pa pair<int,int>
using namespace std; const int maxn=100000+5; int n,G,cnt,tim,w[maxn<<1],hd[maxn],to[maxn<<1],nxt[maxn<<1];
int be[maxn],en[maxn],siz[maxn],sub[maxn],maxsiz[maxn];
long long ans,dis[maxn]; set< pair<int,int> > s; set< pair<int,int> >::iterator it; struct M{
int l,r,Min;
}tree[maxn<<2]; inline void add(int x,int y,int s){
w[cnt]=s;to[cnt]=y;nxt[cnt]=hd[x];hd[x]=cnt++;
} inline void dfs(int x,int fa){
siz[x]=1;
for(int i=hd[x];i!=-1;i=nxt[i])
if(to[i]!=fa)
dfs(to[i],x),siz[x]+=siz[to[i]],maxsiz[x]=max(maxsiz[x],siz[to[i]]);
maxsiz[x]=max(maxsiz[x],n-siz[x]);
} inline void findG(void){
G=1;
for(int i=2;i<=n;i++)
if(maxsiz[G]>maxsiz[i]) G=i;
} inline void dfs(int x,int fa,int top){
sub[x]=top;siz[x]=1;be[x]=++tim;
for(int i=hd[x];i!=-1;i=nxt[i])
if(to[i]!=fa)
dis[to[i]]=dis[x]+w[i],dfs(to[i],x,top),siz[x]+=siz[to[i]];
en[x]=tim;
} inline void build(int l,int r,int tr){
tree[tr].l=l,tree[tr].r=r,tree[tr].Min=inf;
if(l==r) return;
int mid=(l+r)>>1;
build(l,mid,tr<<1),build(mid+1,r,tr<<1|1);
} inline void change(int x,int val,int tr){
if(tree[tr].l==tree[tr].r){
tree[tr].Min=val;return;
}
int mid=(tree[tr].l+tree[tr].r)>>1;
if(x<=mid)
change(x,val,tr<<1);
else
change(x,val,tr<<1|1);
tree[tr].Min=min(tree[tr<<1].Min,tree[tr<<1|1].Min);
} inline int query(int l,int r,int tr){
if(l>r) return inf;
if(tree[tr].l==l&&tree[tr].r==r)
return tree[tr].Min;
int mid=(tree[tr].l+tree[tr].r)>>1;
if(r<=mid)
return query(l,r,tr<<1);
else if(l>mid)
return query(l,r,tr<<1|1);
else
return min(query(l,mid,tr<<1),query(mid+1,r,tr<<1|1));
} inline void Minus(int x){
s.erase(s.find(Pa(siz[x],x)));
siz[x]--;
s.insert(Pa(siz[x],x));
} signed main(void){
#ifndef ONLINE_JUDGE
freopen("in.txt","r",stdin);
#endif
scanf("%d",&n);
memset(hd,-1,sizeof(hd));
for(int i=1,x,y,l;i<n;i++)
scanf("%d%d%d",&x,&y,&l),add(x,y,l),add(y,x,l);
dfs(1,0);findG();memset(siz,0,sizeof(siz));be[G]=++tim;
for(int i=hd[G];i!=-1;i=nxt[i]) dis[to[i]]=dis[G]+w[i],dfs(to[i],G,to[i]),siz[G]+=siz[to[i]],siz[to[i]]<<=1;siz[G]++;siz[G]<<=1;
for(int i=hd[G];i!=-1;i=nxt[i]) s.insert(Pa(siz[to[i]],to[i]));s.insert(Pa(siz[G],G));
build(1,n,1);en[G]=be[G];sub[G]=G;
for(int i=1;i<=n;i++) ans+=dis[i]<<1;
cout<<ans<<endl;
for(int i=1;i<=n;i++) change(be[i],i,1);
for(int i=1,x;i<=n;i++){
Minus(sub[i]);
it=s.lower_bound(Pa(n-i+1,0));
if(it!=s.end()&&it->first==n-i+1)
x=query(be[it->second],en[it->second],1);
else
x=min(query(1,be[sub[i]]-1,1),query(en[sub[i]]+1,n,1)),x=min(x,query(be[G],be[G],1));
printf("%d ",x);Minus(sub[x]);change(be[x],inf,1);
}
return 0;
}
By NeighThorn
51Nod 1558 树中的配对的更多相关文章
- [51nod][cf468D]1558 树中的配对
http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1558 不是很懂dalao们用线段树是怎么写的…… 反正找出重心以后每个子 ...
- 51nod 2494 最长配对
小b有一个01序列,她想找到一个最长的区间使得这个区间的01能两两配对,即0的个数和1的个数相等.求最长区间的长度. 收起 输入 第一行一个正整数n,表示数组长度,其中0<n≤50000: ...
- 「题解」「CF468D」树中的配对
目录 题目大意 思路 源代码 本博客除代码之外,来自 skylee 大佬. 题目大意 一棵\(n(n\le10^5)\)个编号为\(1\sim n\)的点的带边权的树,求一个排列\(p_{1\sim ...
- 51Nod 2006 飞行员配对(二分图最大匹配)
链接:http://www.51nod.com/onlineJudge/questionCode.html#!problemId=2006 思路: 二分匹配 注意n m的关系 代码: #include ...
- 51Nod 2006 飞行员配对(二分图最大匹配)
第二次世界大战时期,英国皇家空军从沦陷国征募了大量外籍飞行员.由皇家空军派出的每一架飞机都需要配备在航行技能和语言上能互相配合的2名飞行员,其中1名是英国飞行员,另1名是外籍飞行员.在众多的飞行员中, ...
- 51Nod 1737 配对(树的重心)
http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1737 题意: 思路: 树的重心. 树的重心就是其所以子树的最大的子树结点 ...
- 51nod 2006 飞行员配对
第二次世界大战时期,英国皇家空军从沦陷国征募了大量外籍飞行员.由皇家空军派出的每一架飞机都需要配备在航行技能和语言上能互相配合的2名飞行员,其中1名是英国飞行员,另1名是外籍飞行员.在众多的飞行员中, ...
- 51Nod 2006 飞行员配对(二分图最大匹配)-匈牙利算法
2006 飞行员配对(二分图最大匹配) 题目来源: 网络流24题 基准时间限制:1 秒 空间限制:131072 KB 分值: 0 难度:基础题 收藏 关注 第二次世界大战时期,英国皇家空军从沦陷国 ...
- 51nod 1737配对
题意:给定一个n个点的带边权树, 保证n是偶数,给这个树两两配对,使得配对后的点路径和最大,输出最大值. 其实是个很简单的题,但还是被绊了.这充分说明现在连简单题都做不来了555 单独考虑每条边.每 ...
随机推荐
- 【Python 2 到 3 系列】 关于除法的余数
v2.2 以前,除("/")运算符的返回有两种可能情况,分别是整型和浮点型.操作数的不同,是影响计算结果数据类型的关键. 以 a / b 为例,a.b均为整型,则结果返回整型:a. ...
- #Python编程从入门到实践#第二章笔记
1.变量 (1)变量名只能包含字母.数字和下划线,不能包含空格 (2)不要将python关键字与函数名作为变量名 (3)简短有描述性,避免使用小写字母l和大写字母O (4)python 始终 ...
- C++基础 namespace register bool
1. namespace (1)命令空间 C中的命名空间 在C中只有一个全局作用域 C语言中所有全局标识符共享同一个作用域 标识符之间可能发生冲突 C++中提出了命名空间的概念 命令空间将全局作用域分 ...
- [转]渗透测试tips...零碎的小知识
1.拿到一个待检测的站,你觉得应该先做什么?收集信息whois.网站源IP.旁站.C段网站.服务器系统版本.容器版本.程序版本.数据库类型.二级域名.防火墙.维护者信息另说… 2.mysql的网站注入 ...
- Eclipse 视图---Eclipse教程第05课
关于视图 Eclipse视图允许用户以图表形式更直观的查看项目的元数据. 例如,项目导航视图中显示的文件夹和文件图形表示在另外一个编辑窗口中相关的项目和属性视图. Eclipse 透视图(perspe ...
- 《Cracking the Coding Interview》——第2章:链表——题目3
2014-03-18 02:25 题目:给定一个单链表中间的节点,删掉那个节点. 解法:把后面节点的数据域拷到当前节点来,然后删除后面那个节点.当前节点不是尾巴,所以后面不为空. 代码: // 2.2 ...
- 《数据结构》C++代码 BFS与DFS
BFS,广度优先搜索,一层一层去遍历图,故称广度优先.实现方式:队列. DFS,深度优先搜索,撞墙才回头的遍历,称为深度优先.实现方式:递归(栈). 这两种遍历方式,是访问图的基本方式.如果拿树做对比 ...
- UPX压缩
什么是UPX UPX (the Ultimate Packer for eXecutables)是一款先进的可执行程序文件压缩器,压缩过的可执行文件体积缩小50%-70% ,这样减少了磁盘占用空间.网 ...
- 关于jdk与jre的区别
JDK:Java Development Kit JRE顾名思义是java运行时环境,包含了java虚拟机,java基础类库.是使用java语言编写的程序运行所需要的软件环境,是提供给想运行java程 ...
- Axios & Interceptors & Serialization & CORS & cookie
Axios https://github.com/axios/axios#config-defaults Global axios defaults axios.defaults.baseURL = ...