题目描述

  给你一棵\(n\)个点的树,让你加最少的边,使得图中没有割点。

  要求输出方案。

  \(n\leq 500000\)

题解

  把叶子的权值设为\(1\),其他点设为\(0\),找出带权重心。

  以重心为根DFS,算出每棵子树的叶子节点个数。

  设有\(l\)个叶子节点。易证每棵子树叶子节点个数不会超过\(\lfloor\frac{l}{2}\rfloor\)。

  把子树按叶子节点个数从大到小排序,从第二大的子树开始,每棵子树选一个叶子和前面剩余最多叶子的子树中选一个叶子连一条边。

  易证这样操作完后重心就不是割点,且剩余叶子最多的子树叶子不会超过总剩余叶子个数\(\div 2\)(向上取整)。

  证明的话,显然次大叶子个数$\geq \(最大叶子个数\)-1$。

  然后就每次选两个剩余叶子个数最多的子树连起来就好了。

  时间复杂度:可以做到\(O(n)\)

代码

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<utility>
#include<vector>
#include<queue>
using namespace std;
typedef pair<int,int> pii;
struct graph
{
int v[1000010];
int t[1000010];
int h[500010];
int n;
graph()
{
memset(h,0,sizeof h);
n=0;
}
void clear(int x)
{
for(int i=1;i<=x;i++)
h[i]=0;
n=0;
}
void add(int x,int y)
{
n++;
v[n]=y;
t[n]=h[x];
h[x]=n;
}
};
graph g;
int s[500010];
int f[500010];
int d[500010];
int rt,rtsz;
int tot;
vector<int> b[500010];
int h[500010];
void dfs(int x,int fa)
{
f[x]=fa;
s[x]=0;
if(d[x]==1)
s[x]++;
for(int i=g.h[x];i;i=g.t[i])
if(g.v[i]!=fa)
{
dfs(g.v[i],x);
s[x]+=s[g.v[i]];
}
}
void dfs2(int x)
{
int mx=0;
for(int i=g.h[x];i;i=g.t[i])
if(g.v[i]!=f[x])
{
mx=max(mx,s[g.v[i]]);
dfs2(g.v[i]);
}
mx=max(mx,tot-s[x]);
if(d[x]>1)
{
if(mx<rtsz)
{
rtsz=mx;
rt=x;
}
}
}
void dfs(int x,int fa,int y)
{
if(d[x]==1)
b[y].push_back(x);
else
for(int i=g.h[x];i;i=g.t[i])
if(g.v[i]!=fa)
dfs(g.v[i],x,y);
}
int e[500010];
int cmp(int x,int y)
{
return b[x].size()>b[y].size();
}
vector<int> c[500010];
int ans[500010][2];
priority_queue<pii> q;
void solve()
{
int n;
scanf("%d",&n);
g.clear(n);
for(int i=1;i<=n;i++)
d[i]=0;
for(int i=1;i<=n;i++)
b[i].clear();
for(int i=1;i<=n;i++)
c[i].clear();
int cnt=0;
int x,y;
for(int i=1;i<n;i++)
{
scanf("%d%d",&x,&y);
d[x]++;
d[y]++;
g.add(x,y);
g.add(y,x);
}
dfs(1,0);
tot=s[1];
rtsz=0x7fffffff;
dfs2(1);
int t=0;
for(int i=g.h[rt];i;i=g.t[i])
{
dfs(g.v[i],rt,g.v[i]);
e[++t]=g.v[i];
}
sort(e+1,e+t+1,cmp);
for(int i=1;i<=t;i++)
h[i]=b[e[i]].back();
c[b[e[1]].size()].push_back(1);
int now=b[e[1]].size();
for(int i=2;i<=t;i++)
{
while(!c[now].size())
now--;
int y=c[now].back();
c[now].pop_back();
ans[++cnt][0]=b[e[i]].back();
if(b[e[i]].size()>=1)
b[e[i]].pop_back();
c[b[e[i]].size()].push_back(i);
if(b[e[y]].size()==0)
ans[cnt][1]=h[y];
else
ans[cnt][1]=b[e[y]].back();
if(b[e[y]].size()>=1)
b[e[y]].pop_back();
now=max(now,(int)b[e[i]].size());
c[b[e[y]].size()].push_back(y);
if(ans[cnt][0]==ans[cnt][1])
printf("1\n");
}
while(!q.empty())
q.pop();
for(int i=1;i<=t;i++)
if(b[e[i]].size())
q.push(pii(b[e[i]].size(),i));
while(!q.empty()&&q.top().first>=1)
{
pii x=q.top(),y;
q.pop();
if(!q.empty()&&q.top().first>=1)
{
y=q.top();
q.pop();
}
else
if(x.second==1)
y=pii(0,2);
else
y=pii(0,1);
ans[++cnt][0]=b[e[x.second]].back();
b[e[x.second]].pop_back();
if(b[e[y.second]].size()==0)
ans[cnt][1]=h[y.second];
else
{
ans[cnt][1]=b[e[y.second]].back();
b[e[y.second]].pop_back();
}
x.first--;
y.first--;
if(x.first>0)
q.push(x);
if(y.first>0)
q.push(y);
if(ans[cnt][0]==ans[cnt][1])
printf("2\n");
}
printf("%d\n",cnt);
for(int i=1;i<=cnt;i++)
printf("%d %d\n",ans[i][0],ans[i][1]);
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("a.in","r",stdin);
freopen("a.out","w",stdout);
#endif
int t;
scanf("%d",&t);
while(t--)
solve();
return 0;
}

【XSY2785】模型的更多相关文章

  1. ASP.NET MVC with Entity Framework and CSS一书翻译系列文章之第二章:利用模型类创建视图、控制器和数据库

    在这一章中,我们将直接进入项目,并且为产品和分类添加一些基本的模型类.我们将在Entity Framework的代码优先模式下,利用这些模型类创建一个数据库.我们还将学习如何在代码中创建数据库上下文类 ...

  2. ASP.NET Core MVC/WebAPi 模型绑定探索

    前言 相信一直关注我的园友都知道,我写的博文都没有特别枯燥理论性的东西,主要是当每开启一门新的技术之旅时,刚开始就直接去看底层实现原理,第一会感觉索然无味,第二也不明白到底为何要这样做,所以只有当你用 ...

  3. ASP.NET路由模型解析

    大家好,我又来吹牛逼了 ~-_-~ 转载请注明出处:来自吹牛逼之<ASP.NET路由模型解析> 背景:很多人知道Asp.Net中路由怎么用的,却不知道路由模型内部的运行原理,今天我就给大家 ...

  4. 高性能IO模型浅析

    高性能IO模型浅析 服务器端编程经常需要构造高性能的IO模型,常见的IO模型有四种: (1)同步阻塞IO(Blocking IO):即传统的IO模型. (2)同步非阻塞IO(Non-blocking  ...

  5. 探索ASP.NET MVC5系列之~~~4.模型篇---包含模型常用特性和过度提交防御

    其实任何资料里面的任何知识点都无所谓,都是不重要的,重要的是学习方法,自行摸索的过程(不妥之处欢迎指正) 汇总:http://www.cnblogs.com/dunitian/p/4822808.ht ...

  6. 隐马尔科夫模型python实现简单拼音输入法

    在网上看到一篇关于隐马尔科夫模型的介绍,觉得简直不能再神奇,又在网上找到大神的一篇关于如何用隐马尔可夫模型实现中文拼音输入的博客,无奈大神没给可以运行的代码,只能纯手动网上找到了结巴分词的词库,根据此 ...

  7. webapi - 模型验证

    本次要和大家分享的是webapi的模型验证,讲解的内容可能不单单是做验证,但都是围绕模型来说明的:首先来吐槽下,今天下午老板为自己买了套新办公家具,看起来挺好说明老板有钱,不好的是我们干技术的又成了搬 ...

  8. 谈谈一些有趣的CSS题目(二)-- 从条纹边框的实现谈盒子模型

    开本系列,讨论一些有趣的 CSS 题目,抛开实用性而言,一些题目为了拓宽一下解决问题的思路,此外,涉及一些容易忽视的 CSS 细节. 解题不考虑兼容性,题目天马行空,想到什么说什么,如果解题中有你感觉 ...

  9. 【NLP】蓦然回首:谈谈学习模型的评估系列文章(一)

    统计角度窥视模型概念 作者:白宁超 2016年7月18日17:18:43 摘要:写本文的初衷源于基于HMM模型序列标注的一个实验,实验完成之后,迫切想知道采用的序列标注模型的好坏,有哪些指标可以度量. ...

随机推荐

  1. H5 32-百度首页

    32-百度首页 新 闻 网 页 贴 吧 知 道 音 乐 图 片 视 频 地 图 百科 文库 hao123 | 更多>> 百度地图带你吃喝玩乐,全心全意为人民服务 把百度设为主页 安装百度卫 ...

  2. H5 表单标签

    33-表单标签3 列表数据 注意点: 1.下拉列表不能输入内容, 但是可以直接在列表中选择内容 2.可以通过给option标签添加一个selected属性来指定列表的默认值 3.可以通过给option ...

  3. c++学习之字符串拼接

    在这里,强调这样一个问题: 可以看出,c++中,定义了string类,string 类方便我们进行字符串的一些操作,而不是像C语言中采用字符数组的方式或者指针的方式,通过上面的一些描述,可以发现: s ...

  4. Python学习资源汇总,转载自他人

    python3英文视频教程(全87集) http://pan.baidu.com/s/1dDnGBvV python从入门到精通视频(全60集)链接:http://pan.baidu.com/s/1e ...

  5. Linux下查看文件系统磁盘使用

    [root@localhost ~]# df -h 可以查看所有文件系统的磁盘使用情况 du --max-depth=1 -h 可以查看当前目录下各子目录的磁盘使用情况 参考:http://www.2 ...

  6. haoop笔记

    : //:什么是hadoop? hadoop是解决大数据问题的一整套技术方案 :hadoop的组成? 核心框架 分布式文件系统 分布式计算框架 分布式资源分配框架 hadoop对象存储 机器计算 :h ...

  7. 分布式ID生成系统 UUID与雪花(snowflake)算法

    Leaf——美团点评分布式ID生成系统 -https://tech.meituan.com/MT_Leaf.html 网游服务器中的GUID(唯一标识码)实现-基于snowflake算法-云栖社区-阿 ...

  8. Azure系列2.1.1 —— BlobContainerPermissions

    (小弟自学Azure,文中有不正确之处,请路过各位大神指正.) 网上azure的资料较少,尤其是API,全是英文的,中文资料更是少之又少.这次由于公司项目需要使用Azure,所以对Azure的一些学习 ...

  9. mac 中登陆mysql忘记密码解决办法

    1.打开终端,输入命令:cd /usr/local/mysql/bin 2.mysql -uroot -p,用这条命令登陆时报错信息: 报错:Enter password: ERROR 1045 (2 ...

  10. cookie,localStorage和sessionStorage区别

    三者的异同 特性 Cookie localStorage sessionStorage 数据的生命期 一般由服务器生成,可设置失效时间.如果在浏览器端生成Cookie,默认是关闭浏览器后失效 除非被清 ...