首页 > 其他分享 >Maximum Control (medium)

Maximum Control (medium)

时间:2024-10-17 10:43:57浏览次数:7  
标签:Control medium val int 染色 void tr Maximum fa

算法

转化题意, 即为

求树上最长不重链覆盖

长链剖分

显然可以使用长链剖分的思想, 直接剖分后贪心的求最大链即可

代码

#include <bits/stdc++.h>
using namespace std;

#define ll long long
const int maxn = 1e5 + 5;
int n, u, v, rt, d[maxn], son[maxn], h[maxn];
int head[maxn], cnt;
struct edge
{
    int to, next;
} e[maxn << 1];
vector<int> val;

void adde(int u, int v)
{
    e[++cnt].to = v;
    e[cnt].next = head[u];
    head[u] = cnt;
}

void dfs1(int u, int fa)
{
    d[u] = d[fa] + 1;
    int num = 0;
    for (int i = head[u]; i; i = e[i].next)
    {
        int v = e[i].to;
        if (v == fa)
            continue;
        dfs1(v, u);
        num++;
    }
    if (!num)
    {
        if (!rt || d[u] >= d[rt])
            rt = u;
    }
}

void dfs2(int u, int fa)
{
    d[u] = d[fa] + 1;
    h[u] = d[u];
    for (int i = head[u]; i; i = e[i].next)
    {
        int v = e[i].to;
        if (v == fa)
            continue;
        dfs2(v, u);
        h[u] = max(h[u], h[v]);
        if (!son[u])
            son[u] = v;
        else if (h[son[u]] < h[v])
            son[u] = v;
    }
}

void dfs3(int u, int fa, int tp)
{
    if (!son[u])
    {
        val.push_back(d[u] - d[tp]);
        return;
    }
    dfs3(son[u], u, tp);
    for (int i = head[u]; i; i = e[i].next)
    {
        int v = e[i].to;
        if (v == fa)
            continue;
        if (v == son[u])
            continue;
        dfs3(v, u, u);
    }
}

int main()
{
    scanf("%d", &n);
    for (int i = 1; i < n; i++)
    {
        scanf("%d%d", &u, &v);
        adde(u, v);
        adde(v, u);
    }
    rt = 0;
    ll ans = 0;
    dfs1(1, 0);
    dfs2(rt, 0);
    dfs3(rt, 0, 0);
    printf("1 ");
    sort(val.begin(), val.end(), greater<int>());
    for (int i = 2; i <= n; i++)
    {
        if (i - 2 < val.size())
            ans += val[i - 2];
        printf("%lld ", ans);
    }
    return 0;
}

总结

善于转化题意, 可以简化做题

线段树上二分

观察题目

\(k = 1\) 时, 答案为 \(1\)
\(k = 2\) 时, 答案为 树的直径的长度

\(k = 3, 4, 5 \cdots\) 时, 答案为距离已被染色的点最远的未被染色的点在染色链的长度

容易发现当以直径的一端为根节点时, 当一个点没有被染色时, 其子树一定也没被染色
所以考虑使用线段树维护每个点距离已经染色过的点的最近距离

每次在线段树上二分查找最近距离最远的点, 然后染色(注意用线段树维护树, 类似于树链剖分的思想, 使用 dfn 序维护), 注意自己未被染色时, 距离未被染色的点至少为 \(1\), 最初建立线段树时要做一遍 dfs , 找到每个点与根节点的最短距离
注意在染色之后, 要一直沿着向上的链找第一个染色的 \(father\) 节点, 在向上的过程中, 将途经的点距离已经染色过的点的最近距离修改为 \(0\), 将其(这里指途经的点)子树距离染色过的点的最短距离修改为其(这里指子树的点)原本距离 - \(1\) [自己(这里指子树上的点)还未染色]

即为

        int u = id[binary(1)];
        if (mrk[u])
            break;
        while (!mrk[u])
        {
            int Val = query(1, app[u]);
            modify(1, app[u], app[u], Val);
            for (int k : G[u])
                if (k != fa[u] && !mrk[k])
                {
                    int val = query(1, app[k]);
                    modify(1, app[k], app[k] + siz[k] - 1, val - 1);
                }
            mrk[u] = true, u = fa[u];
            ++ans;
        }

代码

没时间写了, 什么时候把 lhs 解决掉才能写这种题(

#include <cstdio>
#include <vector>
#include <algorithm>

using std::max;

const int MAXN = 1e5 + 5;

int n;
int val[MAXN << 1];

std::vector<int> G[MAXN << 1];

int siz[MAXN << 1], fa[MAXN << 1];
int app[MAXN << 1], id[MAXN << 1], cnt;
bool mrk[MAXN << 1];

void dfs(int u, int father)
{
    app[u] = ++cnt, siz[u] = 1, id[cnt] = u;
    if (!mrk[u])
        val[u] = val[fa[u] = father] + 1;
    for (int k : G[u])
        if (k != father)
            dfs(k, u), siz[u] += siz[k];
}

namespace SGT
{
#define ls(u) (u << 1)
#define rs(u) (u << 1 | 1)

    struct Sgt
    {
        int l, r, mx, tag;
    } tr[MAXN << 2];

    void pushup(int u)
    {
        tr[u].mx = max(tr[ls(u)].mx, tr[rs(u)].mx);
    }

    void upd(int u, int val)
    {
        tr[u].mx -= val, tr[u].tag += val;
    }

    void pushdown(int u)
    {
        upd(ls(u), tr[u].tag), upd(rs(u), tr[u].tag);
        tr[u].tag = 0;
    }

    void build(int u, int l, int r)
    { 
        tr[u].l = l, tr[u].r = r;
        if (l == r)
            return tr[u].mx = val[id[l]], void();
        int mid = l + r >> 1;
        build(ls(u), l, mid), build(rs(u), mid + 1, r);
        pushup(u);
    }

    int binary(int u)
    {
        if (tr[u].l == tr[u].r)
            return tr[u].l;
        pushdown(u);
        return binary(tr[ls(u)].mx > tr[rs(u)].mx ? ls(u) : rs(u));
    }

    void modify(int u, int l, int r, int val)
    {
        if (tr[u].l >= l && tr[u].r <= r)
            return upd(u, val);
        pushdown(u);
        int mid = tr[u].l + tr[u].r >> 1;
        if (r <= mid)
            modify(ls(u), l, r, val);
        else if (l > mid)
            modify(rs(u), l, r, val);
        else
            modify(ls(u), l, r, val), modify(rs(u), l, r, val);
        pushup(u);
    }

    int query(int u, int x)
    {
        if (tr[u].l == tr[u].r)
            return tr[u].mx;
        pushdown(u);
        int mid = tr[u].l + tr[u].r >> 1;
        if (x <= mid)
            return query(ls(u), x);
        else
            return query(rs(u), x);
    }
}
using SGT::modify, SGT::binary, SGT::query;

int rt;
int ans;

namespace D
{
    int st, ed;
    bool flg;
    int mx;

    void dfs1(int u, int father, int dis)
    {
        if (dis > mx)
            mx = dis, st = u;
        for (int k : G[u])
            if (k != father)
                dfs1(k, u, dis + 1);
    }

    void dfs2(int u, int father, int dis)
    {
        if (dis > mx)
            mx = dis, ed = u;
        for (int k : G[u])
            if (k != father)
                dfs2(k, u, dis + 1);
    }

    void DFS(int u, int father, int ed)
    {
        mrk[u] = true;
        if (u == ed)
            return flg = true, void();
        for (int k : G[u])
            if (k != father)
            {
                DFS(k, u, ed);
                if (flg)
                    return;
            }
        mrk[u] = false;
    }

    void Get()
    {
        dfs1(1, 0, 1), mx = 0, dfs2(st, 0, 1), DFS(st, 0, ed);
        rt = st, printf("%d ", ans = mx);
    }
}

int main()
{

    scanf("%d", &n);
    if (n == 1)
        return puts("1"), 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);
    }
    printf("1 ");
    D::Get();
    dfs(rt, 0);
    SGT::build(1, 1, n);
    int cnt = 3;
    for (; cnt <= n; ++cnt)
    {
        int u = id[binary(1)];
        if (mrk[u])
            break;
        while (!mrk[u])
        {
            int Val = query(1, app[u]);
            modify(1, app[u], app[u], Val);
            for (int k : G[u])
                if (k != fa[u] && !mrk[k])
                {
                    int val = query(1, app[k]);
                    modify(1, app[k], app[k] + siz[k] - 1, val - 1);
                }
            mrk[u] = true, u = fa[u];
            ++ans;
        }
        printf("%d ", ans);
    }
    for (; cnt <= n; ++cnt)
        printf("%d%c", n, " \n"[cnt == n]);

    return 0;
}

总结

此题借鉴了树链剖分的思路, 但与树链剖分完全不同
注意树上处理问题时

  • 关注深度
  • 关注根节点
  • 在修改时, 注意子树的变化也需要修改

树上问题中, 线段树可以用来

  • 树链剖分, 高效维护一颗树
  • \(\log n\) 的寻找一些可并的信息(本题中为 "最近距离最远的点")

代码当然非常难搞, 以后再说

标签:Control,medium,val,int,染色,void,tr,Maximum,fa
From: https://www.cnblogs.com/YzaCsp/p/18471362

相关文章

  • 库卡ForceTorqueControl(一)
    1.功能说明ForceTorqueControl是一个可后载入的备选软件包,具有下列功能:执行取决于测得的过程力和力矩的运动遵守过程力和力矩,不取决于工件的位置和尺寸遵守加工工件期间复杂的过程力变化沿着根据测得的过程力编程的轨迹调整速度通过对机器人柔韧性的编程补偿工件的......
  • 针对所有的controller 添加出入参log日志打印
    packagecom.aide.web.tool;importlombok.extern.slf4j.Slf4j;importorg.aspectj.lang.ProceedingJoinPoint;importorg.aspectj.lang.annotation.Around;importorg.aspectj.lang.annotation.Aspect;importorg.springframework.stereotype.Component;importjava.ut......
  • 过滤器拦截器拦截了request后,controller的@RequestBody 无法获取request内容,报错 Requ
    SpringMVC的拦截器、过滤器、Controller之间的关系 众所周知所有的post请求中的body参数是已流形式存在的,而流数据只能读取一次(为啥看这里),如果在拦截器和过滤器中需要对post参数进行处理的话,就会报Requiredrequestbodyismissing异常。既然知道原因,那只要能将流保存起来......
  • Maximum Rating
    通过这道题,对Splay有了更深刻的理解Splay的中序遍历代表当前序列,通过查询排名为i的点找到序列中的第i个数,这些信息是完全由Splay的结构提供的通过Splay的编号,我们则可以访问到原序列对应的节点其实这道题完全是可以用线段树做的,既然普通线段树不行,那不妨用权值线段树实现【顺......
  • Boost Data Visualization with a New Gauge Control
    BoostDataVisualizationwithaNewGaugeControlCodejockToolkitPro24.0.0helpsusersexperiencemodern,customizablegaugesthatbringdatatolife,inasingle,versatilecomponent.CodejockToolkitProisacomprehensivesuiteofUIcomp......
  • 题解 QOJ5048【[ECFinal19K] All Pair Maximum Flow】
    题目描述给你一个\(n\)个点\(m\)条边的图,它是平面上的正\(n\)边形和一些对角线,节点按逆时针方向编号为\(1\)到\(n\)。对角线只可能在节点处相交。每条边有一个容量,求每个点对之间的最大流的和。\(n\leq200000,m\leq400000\)。solution做法每次找出边权最小的边\(......
  • CAN(Controller Area Network)总线的仲裁机制
    CAN(ControllerAreaNetwork)总线的仲裁机制是其核心特性之一,它确保了在多节点环境中数据能够高效、公正地传输。以下是对CAN仲裁机制的详细解释和介绍:一、仲裁机制概述在CAN总线网络中,各个节点地位平等,没有固定的主节点或从节点之分。这种设计使得每个节点在需要时都可以试图......
  • 帝国CMS建立模型字段报错:Row size too large. The maximum row size for the
    在帝国CMS中建立模型字段时,如果字段过多或单个字段过长,可能会遇到MySQL报错“Rowsizetoolarge”。这个错误是因为MySQL表的最大行大小限制为65535字节(不包括BLOB和TEXT类型字段)。解决这个问题的方法是将一些字段转换为TEXT或BLOB类型。解决方案分析现有字段......
  • #1118 - Row size too large. The maximum row size for the used table type, not co
    这个问题表示在MySQL中,表的一行数据大小超过了最大限制65535字节。这通常是因为表中的某些字段过长导致的。下面是一些解决方法:调整字段类型:将一些较大的字段改为TEXT或BLOB类型。这些类型的存储方式不同于普通字段,可以避免占用过多的行内空间。拆分字段:如果某个字段包含多......
  • Kubernetes从零到精通(16-扩展-CRD、Custom Controller)
    目录一、简介二、CRD1.CRD介绍2.CRD工作流程三、CustomController1.CustomController介绍2.CustomController工作流程四、示例1.创建CR2.配置权限RBAC3.创建CustomController3.1Go项目初始化3.2 main.go编写3.3构建镜像3.4部署Controller4.测试CR和控......