题目链接

分析:

想了好久~~~还是得看题解...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 树中的配对的更多相关文章

  1. [51nod][cf468D]1558 树中的配对

    http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1558 不是很懂dalao们用线段树是怎么写的…… 反正找出重心以后每个子 ...

  2. 51nod 2494 最长配对

    小b有一个01序列,她想找到一个最长的区间使得这个区间的01能两两配对,即0的个数和1的个数相等.求最长区间的长度. 收起   输入 第一行一个正整数n,表示数组长度,其中0<n≤50000: ...

  3. 「题解」「CF468D」树中的配对

    目录 题目大意 思路 源代码 本博客除代码之外,来自 skylee 大佬. 题目大意 一棵\(n(n\le10^5)\)个编号为\(1\sim n\)的点的带边权的树,求一个排列\(p_{1\sim ...

  4. 51Nod 2006 飞行员配对(二分图最大匹配)

    链接:http://www.51nod.com/onlineJudge/questionCode.html#!problemId=2006 思路: 二分匹配 注意n m的关系 代码: #include ...

  5. 51Nod 2006 飞行员配对(二分图最大匹配)

    第二次世界大战时期,英国皇家空军从沦陷国征募了大量外籍飞行员.由皇家空军派出的每一架飞机都需要配备在航行技能和语言上能互相配合的2名飞行员,其中1名是英国飞行员,另1名是外籍飞行员.在众多的飞行员中, ...

  6. 51Nod 1737 配对(树的重心)

    http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1737 题意: 思路: 树的重心. 树的重心就是其所以子树的最大的子树结点 ...

  7. 51nod 2006 飞行员配对

    第二次世界大战时期,英国皇家空军从沦陷国征募了大量外籍飞行员.由皇家空军派出的每一架飞机都需要配备在航行技能和语言上能互相配合的2名飞行员,其中1名是英国飞行员,另1名是外籍飞行员.在众多的飞行员中, ...

  8. 51Nod 2006 飞行员配对(二分图最大匹配)-匈牙利算法

    2006 飞行员配对(二分图最大匹配) 题目来源: 网络流24题 基准时间限制:1 秒 空间限制:131072 KB 分值: 0 难度:基础题  收藏  关注 第二次世界大战时期,英国皇家空军从沦陷国 ...

  9. 51nod 1737配对

    题意:给定一个n个点的带边权树,  保证n是偶数,给这个树两两配对,使得配对后的点路径和最大,输出最大值. 其实是个很简单的题,但还是被绊了.这充分说明现在连简单题都做不来了555 单独考虑每条边.每 ...

随机推荐

  1. Laravel操作上传文件的方法

    1.获取上传的文件 $file=$request->file('file');2.获取上传文件的文件名(带后缀,如abc.png) $filename=$file->getClientOr ...

  2. 【PHP项目】$_SEVER详解

    $_SERVER['HTTP_ACCEPT_LANGUAGE']//浏览器语言 $_SERVER['REMOTE_ADDR'] //当前用户 IP . $_SERVER['REMOTE_HOST'] ...

  3. 插入排序算法Java实现

    一. 算法描述 插入即表示将一个新的数据插入到一个有序数组中,并继续保持有序.例如有一个长度为N的无序数组,进行N-1次的插入即能完成排序:第一次,数组第1个数认为是有序的数组,将数组第二个元素插入仅 ...

  4. TouTiao开源项目 分析笔记20 问答详情

    1.效果预览 1.1.效果预览,从问答列表开始 前面实现了从列表到内容. 这里主要讲解从内容到详情. 点击每一个回答内容,进入回答详情页面. 1.2.触发的点击事件 在WendaContentView ...

  5. TouTiao开源项目 分析笔记10 实现通用普通文章片段页面

    1.RxJava的Observable数据操作符总结 1.1.Map操作符 Map操作符对原始Observable发射的没一项数据应用一个你选择的函数, 然后返回一个发射这些结果的Observable ...

  6. 一、MySQL数据库之简介和安装

    一.基础部分 1.数据库是简介     之前所学,数据要永久保存,比如用户注册的用户信息,都是保存于文件中,而文件只能存在于某一台机器上. 如果我们不考虑从文件中读取数据的效率问题,并且假设我们的程序 ...

  7. 3 破解密码,xshell连接

    1.破解root密码 (1)启动电脑,按上下键进入启动菜单界面,选择第二个Red Hat Enterprise Linux Server, with Linux 0-rescue-* (2)按 'e' ...

  8. 页面引入外部字体ttf,如何提取所需要的ttf字体或者加载过慢的解决方法-1127更新

    最近几天编写手机端的页面之后,文中需要华文行楷字体,在网上下载后,引入到了自己的前端页面,以为没有什么事了,继续码代码 @font-face { font-family:huawen; src: ur ...

  9. easyui-datagrid单选模式下隐藏表头的全选框

    easyui-datagrid可以不使用复选框来进行单选,直接使用onSelect和 singleSelect:true就可以实现单选,但是有一些用户会比较习惯使用勾选框,这时会加一列checkbox ...

  10. 《Cracking the Coding Interview》——第6章:智力题——题目2

    2014-03-19 06:57 题目:对于8x8的棋盘,如果拿掉对角位置的两个小块儿,能否用1x2的多米诺牌拼成剩下的棋盘? 解法:不可能.且不说8x8,NxN都是不可能的.如果N是奇数,NxN-2 ...