题目描述

  给你一棵\(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. Minesweeper

    你玩过扫雷吗?这个可爱的小游戏带有一个我们记不住名字的操作系统.游戏的目标是找到所有地雷在M x N场中的位置.游戏在一个正方形中显示一个数字,它告诉你在这个正方形附近有 多少个地雷.每个方块最多有八 ...

  2. LookupError: Resource averaged_perceptron_tagger not found. Please use the NLTK Downloader to obtain the resource:

    命令行执行 import nltk nltk.download('averaged_perceptron_tagger') 完事

  3. Socket编程,SocketServer模块

    一.SocketServer的几种类型 面向远程: TCP 协议链接:socketserver.TCPServer(server_address, RequestHandlerClass, bind_ ...

  4. Mysql drop function xxxx ERROR 1305 (42000): FUNCTION (UDF) xxxx does not exist

    mysql> drop function GetEmployeeInformationByID;ERROR 1305 (42000): FUNCTION (UDF) GetEmployeeInf ...

  5. :before添加图片,IE8兼容

    这是项目开发中遇到的奇怪的小问题: 在IE8下出现按钮点击后消失了,鼠标点击页面后却又出现: 最初的代码:添加背景图片的方法,这样是存在兼容问题的. 更改后代码:content中添加图片,完美兼容IE ...

  6. MyBatis映射文件1(增删改、insert获取自增主键值)

    增删改 Mybatis为我们提供了<insert>.<update>.<delete>标签来对应增删改操作 在接口中写增删改的抽象方法 void addEmp(Em ...

  7. java学习之—并归排序

    /** * 并归排序 * Create by Administrator * 2018/6/26 0026 * 下午 5:13 **/ public class DArray { private lo ...

  8. python之路--第一类对象,函数名,变量名

    一 . 第一类对象 函数对象可以像变量一样进行赋值 , 还可以作为列表的元素进行使用 可以作为返回值返回 , 可以作为参数进行传递 def func(): def people(): print('金 ...

  9. kibana简单使用——elaticsearch的文档,索引的CRUD操作

    1.初始化索引: #number_of_shards:分片的数量,mo'ren默认为5 #number_of_replicas:副本副本的副本的数量 #shards一旦设置不能修改 PUT lagou ...

  10. 记一次tomcat7.0版本启动项目失败问题

    测试项目在tomcat7中启动失败,报错如下: @794314bc3 Error during job execution (jobs.Bootstrap) Oops: VerifyError ~ p ...