BZOJ4121 乱搞

来源:互联网 发布:淘宝店铺质检报告没有 编辑:程序博客网 时间:2024/05/17 02:59

这道题两问 (我乱猜的第二问 也不知道证的对不对 OJ上交不过 本机测是可以过得 哪位dalao看出错了请指出Orz)

第一问的话 答案是ans=(叶子结点数+1)/2 将叶子节点两两连接就没有度数位1的点 就可以满足
第二问我的思路是找一个度数>=2的点作为根来dfs 遇到叶子节点 ++cnt 并存在数组里 做完后 ans=(cnt+1)/2 将 i与ans+i 连接 如果是奇数个点 (也就是第ans个点没有对应点可以连) 将ans点与1连
下面证明可行性
这里写图片描述
这个图画的比较正常 能说明问题就行了
首先我们把每个叶子结点分类 每个点属于他到根路径上离跟最近的点
这个图 1,2,3,4,5,6属于a 7,8属于b 9,10属于c
有几种情况 下面一一讨论
①i点和 ans+i点不属于同一类 那么两个点的lca在根 也就是说切掉两点间路径上任意一个点 这两个点一定联通 这个图也一定联通 比如(2,7)
②i点和 ans+i点属于同一类 那么i到ans+i之间的都属于同一类
比如说(1,6) 很明显中间属于一类
因为是dfs的 很容易得到 先连上两点 继续向下做直到j和ans+j点时两个点不属于同一类 那么j和ans+j就属于情况① 现在回过头来看i和ans+i 因为j在i和ans+i之间 所以j在i和 ans+i之间 那么lca(i,ans+i)一定是lca(i,j)和lca(j,ans+i)上面(或者相同)的点 如果想使(i和ans+i)不连通 就一定要 切在lca(i,ans+i)到根路径上的边 这样他两才有可能不联通 如果切断 通过上面lca的判断 lca(i,ans+i)的儿子点一定可以不经过lca(i,ans+i)移动到j点 这样就和ans+j联通了 也就和整棵树联通了
③每队i和ans+i独属于同一类 很明显这种情况就是所有儿子都属于同一类 那岂不是说根只有一个儿子 这不满足我们一开始选取度数大于2的点作为根的条件 矛盾
④如果ans位奇数 那ans点和第一个叶子结点连就好了 这个很明显成立

这几种情况都说明了 不管切那个边 如果i和ans+i 都在之下 那就情况②证明 如果只有一个在 那直接通过我们之前连接的边就能和树联通
所以贪心成立 也一定有连接ans次的方案(之前我们只是假设 现在说明一定可行)

下面贴代码 很好写

#include<bits/stdc++.h>using namespace std;const int N=5e5+5;int n,tot=1,cnt,ans,tt;int head[N],tmp[N],in[N];bool vis[N];queue<int>s;struct Egde{    int v,nxt;}e[N*2];inline int read(){    int x=0,f=1;char ch=getchar();    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}    return x*f;}void add(int u,int v){    e[++tot].v=v;e[tot].nxt=head[u];head[u]=tot;in[v]++;    e[++tot].v=u;e[tot].nxt=head[v];head[v]=tot;in[u]++;}void bfs(){    for(int i=1;i<=n;i++){        if(in[i]>=2){            s.push(i);vis[i]=1;break;        }    }     while(!s.empty()){        int x=s.front();s.pop();        if(in[x]==1) tmp[++cnt]=x;        for(int i=head[x];i;i=e[i].nxt){            int j=e[i].v;            if(!vis[j]){                vis[j]=1;                s.push(j);             }        }    }}int main(){/*  freopen("data.in","r",stdin);    freopen("data.out","w",stdout);*/    n=read();    for(int i=1,x,y;i<n;i++) x=read(),y=read(),add(x,y);    bfs();    ans=(cnt+1)>>1;    cout<<ans<<endl;    for(int i=1;i<=ans;i++){        if(i*2<=cnt)        printf("%d %d\n",tmp[i],tmp[ans+i]);        else         printf("%d %d\n",tmp[1],tmp[ans]);    } }
原创粉丝点击