zoukankan      html  css  js  c++  java
  • [CF1228F](One Node is Gone)

    题意

        定义一颗被删去一个节点的树为:原本有一个满二叉树,选择一个节点,断开它和父亲孩子的连边,然后该节点父亲与该节点的两个孩子分别连边

         现在给你一颗被树,要判断这棵树是不是被删去一个节点的树,如果是,求出有多少种可能被删去的节点及被删去的节点的父亲(有多种可能节点的话按编号排序输出)

    solution

        background:

         一道syk眼中的签到水题树上乱搞好题

         可能是最近码力上来了水题做多了,居然没写挂

         solution:

         首先要遍历树,就得找到原来的根。显然原来的根在直径中点上,如果有两个中点就都要搜一遍。

         对于一个节点,我们记两个值 op 和 h,表示该点的子树内是否少了一个点和最大深度

         然后按照该点有0/1/2/3个孩子讨论一波就好了(以下省略awa)

         自己画图理解吧,当然代码里也有注释

    code

        

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<vector>
    #define N 200000
    using namespace std;
    struct zero{
        int nxt,to;
    }edge[N<<1];
    int head[N],tot=0;
    void add_edge(int a,int b){edge[++tot]=(zero){head[a],b};head[a]=tot;}
    int n,m,plk,poi,d1,d2,dep[N],kl[N],d[N],op[N],h[N];
    bool flag;
    void aux(int x,int fa){
      if(dep[x]>plk)plk=dep[x],poi=x;
      for(int i=head[x];i;i=edge[i].nxt){
          int to=edge[i].to;
          if(to==fa)continue;
          dep[to]=dep[x]+1;
          kl[to]=x;
          aux(to,x);
      }
    }
    bool cmp(int a,int b){return h[a]<h[b];}
    void solve(int x,int fa){//这里flag=0就是GG(不可行)了
        vector<int> v;
        for(int i=head[x];i;i=edge[i].nxt){
            int to=edge[i].to;
            if(to==fa)continue;
            v.push_back(to);
        }
        op[x]=0;
        if(v.size()==0)h[x]=op[x]=0;//叶子节点,什么事都没有
        else if(v.size()==1){
            int to=v[0];
            solve(to,x);
            if(op[to]||h[to])flag=0;
            op[x]=x,h[x]=h[v[0]]+1;//一个孩子,那肯定少了一边,所以只有另一个孩子没有问题且少的孩子是叶子结点才不会GG
        }
        else if(v.size()==2){
            solve(v[0],x),solve(v[1],x);
            if((op[v[0]]&&op[v[1]])||h[v[0]]!=h[v[1]])flag=0;
            else if(op[v[0]]||op[v[1]])op[x]=op[v[0]]+op[v[1]];//两个孩子,该节点的op取决于孩子的op
            h[x]=h[v[0]]+1;
        }
        else if(v.size()==3){
            solve(v[0],x),solve(v[1],x),solve(v[2],x);
            sort(v.begin(),v.end(),cmp);
            if(op[v[0]]||op[v[1]]||op[v[2]])flag=0;
            if(!(h[v[1]]==h[v[0]]&&h[v[2]]==h[v[0]]+1))flag=0;
            op[x]=x,h[x]=h[v[2]]+1;//三个孩子,画个图就会发现只有一种情况不会GG
        }
        else flag=0;
    }
    int main(){
    scanf("%d",&n);
    m=(1<<n)-2;
    for(int i=1;i<m;i++){
        int a,b;
        scanf("%d%d",&a,&b);
        add_edge(a,b),add_edge(b,a);d[a]++,d[b]++;
    }
    poi=plk=dep[1]=0;aux(1,0);d1=poi;
    poi=plk=dep[d1]=kl[d1]=0;aux(d1,0);d2=poi;
    int poss=d2;
    vector<int> syk;
    while(poss){
        if(abs(2*dep[poss]-dep[d2])<=1){
    flag=1;solve(poss,0);//是直径中点
    if(op[poss]&&flag&&h[poss]==n-1)syk.push_back(op[poss]);//注意这里还要判树的深度为n-1
    } poss
    =kl[poss]; } cout<<syk.size()<<endl; sort(syk.begin(),syk.end()); for(int i=0;i<syk.size();i++)cout<<syk[i]<<" "; }
  • 相关阅读:
    React Native 开发豆瓣评分(三)集成 Redux
    React Native 开发豆瓣评分(二)路由配置
    React Native 开发豆瓣评分(一)环境搭建&配置模拟器
    VSCode 搭建 React Native 环境
    webpack4 + ejs 构建多页应用
    react-native 沉浸式状态栏
    react-native——tab配置及跳转
    uni-app 入门之 nvue (weex) 爬坑记
    javascript中bind()、call()、apply()的使用
    mysql数据库中文乱码配置文件解决以及常见mysql命令
  • 原文地址:https://www.cnblogs.com/stepsys/p/11612374.html
Copyright © 2011-2022 走看看