zoukankan      html  css  js  c++  java
  • 「日常训练&知识学习」树的分块(王室联邦,HYSBZ-1086)

    题意与分析

    这题的题意就是树分块,更具体的看题目(中文题)。
    学习这一题是为了树的分块,为树上莫队做铺垫。
    参考1:https://blog.csdn.net/LJH_KOQI/article/details/52326103
    参考2:https://blog.csdn.net/popoqqq/article/details/42772237
    注意到题目要求某块区域所有的点到根的路径上的点都属于该区域。因此不能够暴力地去dfs,每找到(B)个分一块是不可取的,因为无法保证联通性(一颗子树的下半截和另一棵子树的上半截组成一块)。因此,我们需要尽可能地从底部往上去组织块(Block),“每棵子树较深的部分自己成块,然后靠近根的部分组成一个大块”。
    因此这么做:对于一个点(x),以初次访问它时,栈的栈顶作为相对栈底,每遍历完它的一个子节点所在的子树(先遍历完),判断此时栈顶减去相对栈底得到的元素个数是否(ge B),如果成立,那么弹栈至相对栈顶。当访问完所有子节点要回溯到x的父节点时,再把x压入栈。这样一来,一个子树深搜过后,子树内地未分块节点不会超过B,而搜索子树前的未分块节点数也不会超过b,从而每块不会超过(2B);最后dfs结束时剩余的未组成块的节点个数也不会超过b,从而最后一块不会超过(3B),把它们归到最后一个块就可以了。这种分块方法就可以保证连通性和块的大小了。

    代码

    /*
     * Filename: hysbz1086.cpp
     * Date: 2018-11-13
     */
    
    #include <bits/stdc++.h>
    
    #define INF 0x3f3f3f3f
    #define PB push_back
    #define MP make_pair
    #define fi first
    #define se second
    #define rep(i,a,b) for(repType i=(a); i<=(b); ++i)
    #define per(i,a,b) for(repType i=(a); i>=(b); --i)
    #define ZERO(x) memset(x, 0, sizeof(x))
    #define MS(x,y) memset(x, y, sizeof(x))
    #define ALL(x) (x).begin(), (x).end()
    
    #define QUICKIO                  
        ios::sync_with_stdio(false); 
        cin.tie(0);                  
        cout.tie(0);
    #define DEBUG(...) fprintf(stderr, __VA_ARGS__), fflush(stderr)
    
    using namespace std;
    typedef long long ll;
    typedef int repType;
    
    const int MAXN=1005;
    vector<int> G[MAXN];
    int stk[MAXN],top=0;
    int root[MAXN],cnt=0;
    int belong[MAXN];
    int n,b;
    
    void dfs(int now, int pre)
    {
        int bottom=top;
        rep(i,0,int(G[now].size())-1) if(G[now][i]!=pre)
        {
            dfs(G[now][i],now);
            if(top-bottom>=b)
            {
                root[++cnt]=now;
                while(top!=bottom)
                    belong[stk[top--]]=cnt;
            }
        }
        stk[++top]=now;
    }
    
    int
    main()
    {
    QUICKIO
        cin>>n>>b;
        rep(i,1,n-1)
        {
            int u,v; cin>>u>>v;
            G[u].PB(v);
            G[v].PB(u);
        }
        dfs(1,0);
        while(top) // the last block
            belong[stk[top--]]=cnt;
        cout<<cnt<<endl;
        rep(i,1,n)
            cout<<belong[i]<<char(i==n?'
    ':' ');
        rep(i,1,cnt)
            cout<<root[i]<<char(i==cnt?'
    ':' ');
        return 0;
    }
    
    如非注明,原创内容遵循GFDLv1.3发布;其中的代码遵循GPLv3发布。
  • 相关阅读:
    c++ socket 出现绑定失败的一个特殊原因。Bind failed Error:10049
    解决OCX 在 非开发电脑上注册出错的问题
    JAVASCRIPT 调用 其他应用程序的方法
    JAVASCRIPT 调用 OCX 的那些坑
    关于socket通信bind()返回值错误:10049
    WPF LiveChart示例
    .NET Core 2.1 IIS 部署 出现500.19 错误
    文件上传大小限制
    winform httpclient 多文件上传
    VS Code中添加程序集安装包即添加DLL引用
  • 原文地址:https://www.cnblogs.com/samhx/p/Blocked-Tree_HYSBZ-1086.html
Copyright © 2011-2022 走看看