zoukankan      html  css  js  c++  java
  • 【XSY2785】模型

    题目描述

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

      要求输出方案。

      (nleq 500000)

    题解

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

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

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

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

      易证这样操作完后重心就不是割点,且剩余叶子最多的子树叶子不会超过总剩余叶子个数(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
    ");
    	}
    	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
    ");
    	}
    	printf("%d
    ",cnt);
    	for(int i=1;i<=cnt;i++)
    		printf("%d %d
    ",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;
    }
    
  • 相关阅读:
    html基础知识点
    uni-app之tabBar的自己配置
    uni-app之导航配置pages.json
    js获取链接?后边的参数名称或者值
    验证码输入自动聚焦下一个input或者删除自动聚焦上一个input
    VUE中/deep/深度作用域
    vue环境下新建项目
    vue中展示数据
    VUE环境项目搭建以及简单的运行例子
    ios设置音乐audio自动播放
  • 原文地址:https://www.cnblogs.com/ywwyww/p/8611889.html
Copyright © 2011-2022 走看看