题目描述

  给你一棵\(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 58-网页的布局方式

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  2. mybatis 的sql语句及使用mybatis的动态sql mybatis防注入

    由于看到写的比较详细的文档这里将之前的删掉了,只留下一些我认为能帮助理解的和关于动态sql及防注入的一些理解.文档链接  :mybatis官方文档介绍 <!-- 根据条件查询用户 --> ...

  3. Elasticsearch - 简单介绍

    Elasticsearch 简介 1. 什么是 Elasticsearch ElasticSearch 是一个基于 Lucene 的搜索服务器. 它了一个分布式多 用户能力的全文搜索引擎,能够达到实时 ...

  4. 什么是车辆识别代码(VIN)

    车辆识别代码(VIN),VIN是英文Vehicle Identification Number(车辆识别码)的缩写.因为ASE标准规定:VIN码由17位字符组成,所以俗称十七位码.正确解读VIN码,对 ...

  5. java 8 jvm 内存配置

    jdk8内存参数解析与修改(新的参数) - LikeTech - CSDN博客https://blog.csdn.net/lk7688535/article/details/51767333 Java ...

  6. [转帖]震惊,用了这么多年的 CPU 利用率,其实是错的

    震惊,用了这么多年的 CPU 利用率,其实是错的 2018年12月22日 08:43:09 Linuxer_ 阅读数:50 https://blog.csdn.net/juS3Ve/article/d ...

  7. javax.validation.ValidationException: Unable to create a Configuration, because no Bean Validation provider could be found. Add a provider like Hibernate Validator (RI) to your classpath.

    项目依赖 <dependency> <groupId>javax</groupId> <artifactId>javaee-api</artifa ...

  8. php redis常用方法代码例子

    1,connect 描述:实例连接到一个Redis.参数:host: string,port: int返回值:BOOL 成功返回:TRUE;失败返回:FALSE 示例: <?php $redis ...

  9. git简介及安装(win10)

    一句话介绍git Git是Linus Torvalds编写,目前是世界上最先进的分布式版本控制系统. git能干什么? 代码备份.还原,版本管理,分支管理,解决冲突,协同开发... 安装git > ...

  10. linux audit审计(8)--ausearch搜索audit日志文件

    ausearch这个工具,可以针对指定的事件来搜索audit日志文件.默认情况下,ausearch搜索/var/log/audit/audit.log这个文件. The ausearch utilit ...