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;
    }
    
  • 相关阅读:
    vuejs开发环境搭建
    贝塞尔曲线(cubic bezier)
    解决安装mysql的”A Windows service with the name MySQL already exists.“问题
    display:inline-block的间隙问题和解决办法
    限制两行显示,超出部分省略号
    border-radius四个值的问题
    PHP环境搭建
    CSS3属性box-sizing
    -webkit-tap-highlight-color
    gdb命令
  • 原文地址:https://www.cnblogs.com/ywwyww/p/8611889.html
Copyright © 2011-2022 走看看