zoukankan      html  css  js  c++  java
  • uoj #139. 【UER #4】被删除的黑白树 dfs序 贪心

    #139. 【UER #4】被删除的黑白树

    Time Limit: 1 Sec  

    Memory Limit: 256 MB

    题目连接

    http://uoj.ac/problem/139

    Description

    很久很久以前,有一棵树加入了 UOJ 群。

    这天,在它讨论“一棵树应该怎么旋转”的时候一不小心被删除了,变成了被删除的树。

    突然间,它突然发现它失去了颜色,变成了一棵纯白的树。这让它感觉很焦躁,于是它来拜托你给自己染上一些颜色。

    我们可以把它描述为一棵 n 个节点的有根树(默认树的根为 1 号节点),所有非根的度数为 1 的节点被称为叶子节点。最开始所有的节点都是白色的。

    现在你需要选出一些节点并把这些节点染成黑色的。为了迎合树的审美,你的染色方案必须要满足所有叶子节点到根路径上的黑色节点个数相同。

    你发现黑色节点个数越多,树就会越高兴,所以你想要知道在所有合法的染色方案中,黑色节点总个数最多是多少。

    Input

    第一行一个正整数 n 表示树的节点个数。

    接下来的 n−1 行,每行是两个整数 u,v (1≤u,v≤n,u≠v) 表示树上的一条边。

    Output

    一个整数,表示在所有合法方案中黑色节点的最多数量。

    Sample Input

    7
    1 2
    1 3
    2 4
    2 5
    3 6
    3 7

    Sample Output

    7

    HINT

    题意

    题解:

    首先贪心一下,对于每条从叶子到根节点的黑色棋子个数,应该是最浅的叶子节点的深度

    于是我们就可以一次dfs求出这个深度,然后再染色就好了

    染色我比较麻烦,我是用dfs序维护的……

    每次从叶子节点往上染色,先查询一下这个点的祖先已经染了多少个点,然后再慢慢跑的

    代码:

    #include<iostream>
    #include<stdio.h>
    #include<math.h>
    #include<vector>
    #include<algorithm>
    #include<cstring>
    using namespace std;
    typedef long long LL;
    #define LL(x) (x<<1)
    #define RR(x) (x<<1|1)
    #define MID(a,b) (a+((b-a)>>1))
    #define maxn 300005
    vector<int> G[maxn];
    vector<int> P;
    int n;
    struct PPP
    {
        int l,d,r;
    }node[maxn];
    struct Node
    {
        int lft,rht;
        LL sum,add;
        int mid(){return MID(lft,rht);}
        void fun(LL tmp)
        {
            add+=tmp;
            sum+=(rht-lft+1)*tmp;
        }
    };
    
    int y[maxn];
    
    struct Segtree
    {
        Node tree[maxn*4];
        void relax(int ind)
        {
            if(tree[ind].add)
            {
                tree[LL(ind)].fun(tree[ind].add);
                tree[RR(ind)].fun(tree[ind].add);
                tree[ind].add=0;
            }
        }
        void build(int lft,int rht,int ind)
        {
            tree[ind].lft=lft;    tree[ind].rht=rht;
            tree[ind].sum=0;    tree[ind].add=0;
            if(lft==rht) tree[ind].sum=y[lft];
            else
            {
                int mid=tree[ind].mid();
                build(lft,mid,LL(ind));
                build(mid+1,rht,RR(ind));
                tree[ind].sum=tree[LL(ind)].sum+tree[RR(ind)].sum;
            }
        }
        void updata(int st,int ed,int ind,int add)
        {
            int lft=tree[ind].lft,rht=tree[ind].rht;
            if(st<=lft&&rht<=ed) tree[ind].fun(add);
            else
            {
                relax(ind);
                int mid=tree[ind].mid();
                if(st<=mid) updata(st,ed,LL(ind),add);
                if(ed> mid) updata(st,ed,RR(ind),add);
                tree[ind].sum=tree[LL(ind)].sum+tree[RR(ind)].sum;
            }
        }
        LL query(int st,int ed,int ind)
        {
            int lft=tree[ind].lft,rht=tree[ind].rht;
            if(st<=lft&&rht<=ed) return tree[ind].sum;
            else
            {
                relax(ind);
                int mid=tree[ind].mid();
                LL sum1=0,sum2=0;
                if(st<=mid) sum1=query(st,ed,LL(ind));
                if(ed> mid) sum2=query(st,ed,RR(ind));
                return sum1+sum2;
            }
        }
    }seg;
    int cnt = 1;
    int cntt = 1;
    int ans = 9999999;
    bool cmp(int a,int b)
    {
        return node[a].d<node[b].d;
    }
    void dfs3(int x,int fa,int d)
    {
        node[x].l=cntt++;
        node[x].d=d;
        for(int i=0;i<G[x].size();i++)
        {
            if(G[x][i]==fa)
                continue;
            dfs3(G[x][i],x,d+1);
        }
        node[x].r=cntt;
    }
    void dfs(int x,int pre,int add)
    {
        if(G[x].size()==1&&x!=1)
        {
            P.push_back(x);
            ans = min(ans,add);
            return;
        }
        for(int i=0;i<G[x].size();i++)
        {
            int v=G[x][i];
            if(v==pre)continue;
            dfs(v,x,add+1);
        }
    }
    int Ans = 0;
    int vis[maxn];
    void dfs2(int x,int pre,int add)
    {
    
        if(vis[x])return;
        if(add<=0)return;
        vis[x]=1;
        Ans++;
        seg.updata(node[x].l,node[x].r-1,1,1);
        for(int i=0;i<G[x].size();i++)
        {
            int v = G[x][i];
            if(v==pre)continue;
            if(node[v].d >= node[x].d)continue;
            dfs2(v,x,add-1);
        }
    }
    int main()
    {
        //freopen("k.in","r",stdin);
        //freopen("2.out","w",stdout);
        scanf("%d",&n);
        if(n==1)
        {
            printf("1
    ");return 0;
        }
        for(int i=1;i<n;i++)
        {
            int x,y;scanf("%d%d",&x,&y);
            G[x].push_back(y);
            G[y].push_back(x);
        }
        seg.build(1,n,1);
        dfs(1,-1,1);
        dfs3(1,-1,1);
        sort(P.begin(),P.end(),cmp);
        for(int i=0;i<P.size();i++)
        {
    
            int t = 0;
            int xx = seg.query(node[P[i]].l,node[P[i]].l,1);
            if(xx<0)continue;
            if(P[i]!=1)
                t = ans-xx;
            dfs2(P[i],-1,t);
        }
        printf("%d
    ",Ans);
    }
  • 相关阅读:
    ESLint 配置说明
    ThinkPhp 更改 BIT 类型的问题
    sql server management studio 查询的临时文件路径
    Excel分组快速自动填充编号
    ThinikPhp 将数据库模型的增、删、改操作写入日志
    Window 任务栏清除历史记录
    vscode 中使用php-cs-fixer和PHP Formatter 插件规范化PHP代码
    ThinkPhp 使用PhpExcel导出导入多语言文件
    [UE4]抛物线指示器
    [UE4]瞬移
  • 原文地址:https://www.cnblogs.com/qscqesze/p/4906634.html
Copyright © 2011-2022 走看看