首页 > 其他分享 >换根问题

换根问题

时间:2023-05-20 10:35:12浏览次数:40  
标签:hson int 节点 问题 cr 换根 out

例题:P3979 遥远的国度

这是个树上查询子树信息问题。一开始一定会给出一个根,接下来会给出一些换根操作(就是让某个节点作为新的树根),在某个换根操作以后,接下来的操作(就是查询)会按照刚才缓过来的根进行查询。因为不论换根前后,这棵树的整体结构形态不变,变的只是节点与节点之间的父子关系。

但是如果真换根的话(就是每换一次根就重新建一棵树)……显然时间复杂度上不允许。那就搞一些特殊操作。

一开始让1当根(我们存储树的信息都是存储其初始形态)
image
后来让6当根
image

经分析可发现,父子关系发生变化的只有从 \(1\) 到 \(6\) 这条链。

设当前的根是 \(cr\),查询的点是 \(x\),分三种情况:

  1. 如果 \(x == cr\) ,直接输出整个子树。
  2. 如果 \(x \ne cr\) 并且 \(in[\ x\ ] \le ln[\ cr\ ], out[\ cr\ ] \le out[\ x\ ]\) ,( \(in[\ ], out[\ ]\) 是某个节点所管辖的区间),枚举与 \(x\) 相连的儿子节点(因为树的边是双向的,所以一定要把其父亲节点排除),找到某一个子节点 \(y\) ,使得 \(cr\) 在以 \(y\) 为根的子树中,那么 \([\ in[\ y\ ],\ out[\ y\ ]\ ]\) 就是要排除的区间。
  3. 如果不是以上两种情况,那么就直接查询 \([\ in[\ x\ ],\ out[\ x\ ]\ ]\) 就可以。

代码如下:

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

inline int read() {
    int f(1), x(0);
    char c = getchar();
    for (; !isdigit(c); c = getchar()) if (c == '-') f = -1;
    for (; isdigit(c); c = getchar()) x = (x << 3) + (x << 1) + (c & 15);
    return x * f;
}

const int maxn(100005);

int rt, opt, n, m, val[maxn], a, b, c;
int head[maxn], nxt[maxn << 1], ver[maxn << 1], tot;

inline void add(int x, int y) {
    ver[++tot] = y, nxt[tot] = head[x], head[x] = tot;
}

int hson[maxn], siz[maxn], dep[maxn], fa[maxn];
int in[maxn], out[maxn], rin[maxn], cnt, top[maxn];

void dfs1(int x) {
    hson[x] = -1; siz[x] = 1;

    for (int i = head[x]; ~i; i = nxt[i]) {
        int y = ver[i];
        if (dep[y]) continue;

        fa[y] = x;
        dep[y] = dep[x] + 1;
        dfs1(y);

        siz[x] += siz[y];
        if (hson[x] == -1 || siz[y] > siz[hson[x]]) hson[x] = y;
    }
}

void dfs2(int x, int f) {
    top[x] = f;
    in[x] = ++cnt; rin[cnt] = x;

    if (hson[x] == -1) {
        out[x] = cnt;
        return;
    }
    dfs2(hson[x], f);

    for (int i = head[x]; ~i; i = nxt[i]) {
        int y = ver[i];
        if (y != hson[x] && y != fa[x]) dfs2(y, y);
    }

    out[x] = cnt;
}

struct Segtree {
    int l, r;
    int minn, lazy;

    // Segtree() : minn(INT_MAX) {};
} t[maxn << 2];

void pushup(int p) {
    t[p].minn = min(t[p << 1].minn, t[p << 1 | 1].minn);
}

void pushdown(int p) {
    if (t[p].lazy) {
        t[p << 1].lazy = t[p << 1 | 1].lazy = t[p].lazy;
        t[p << 1].minn = t[p << 1 | 1].minn = t[p].lazy;
        t[p].lazy = 0;
    }
}

void build(int p, int l, int r) {
    t[p].l = l; t[p].r = r;
    if (l == r) {
        t[p].minn = val[rin[l]];
        return;
    }

    int mid = (l + r) >> 1;
    build(p << 1, l, mid);
    build(p << 1 | 1, mid + 1, r);
    pushup(p);
}

void change_interval(int p, int l, int r, int v) {
    if (l <= t[p].l && t[p].r <= r) {
        t[p].lazy = t[p].minn = v;
        return;
    }

    pushdown(p);
    int mid = (t[p].l + t[p].r) >> 1;
    if (l <= mid) change_interval(p << 1, l, r, v);
    if (r > mid) change_interval(p << 1 | 1, l, r, v);
    pushup(p);
}

void path_change(int x, int y, int v) {
    while (top[x] != top[y]) {
        if (dep[top[x]] < dep[top[y]]) swap(x, y);
        change_interval(1, in[top[x]], in[x], v);
        x = fa[top[x]];
    }

    if (dep[x] > dep[y]) swap(x, y);
    change_interval(1, in[x], in[y], v);
}

int query_min(int p, int l, int r) {
    if (l <= t[p].l && t[p].r <= r) return t[p].minn;

    pushdown(p);
    int tmp(INT_MAX);
    int mid = (t[p].l + t[p].r) >> 1;
    if (l <= mid) tmp = min(tmp, query_min(p << 1, l, r));
    if (r > mid) tmp = min(tmp, query_min(p << 1 | 1, l, r));
    return tmp;
}

int main() {
    memset(head, 0xff, sizeof(head));
    
    n = read(), m = read();
    for (int i = 1; i < n; ++i) {
        a = read(), b = read();
        add(a, b); add(b, a);
    }

    for (int i = 1; i <= n; ++i) val[i] = read();

    rt = read(); dep[rt] = 1;

    dfs1(rt); dfs2(rt, rt);

    /* for (int i = 1; i <= n; ++i) {
        printf("in[%d] = %d, out[%d] = %d\n", i, in[i], i, out[i]);
    } */

    build(1, 1, n);

    while (m--) {
        opt = read();

        if (opt == 1) {
            rt = read();
        } else if (opt == 2) {
            a = read(), b = read(), c = read();
            path_change(a, b, c);
        } else if (opt == 3) {
            a = read();

            if (a == rt) {
                printf("%d\n", t[1].minn);
            } else if (in[a] <= in[rt] && out[rt] <= out[a]){
                int lc, rc;

                for (int i = head[a]; ~i; i = nxt[i]) {
                    int y = ver[i];
                    if (y == fa[a]) continue; // 排除父节点

                    if (in[y] <= in[rt] && out[rt] <= out[y]) {
                        lc = in[y]; rc = out[y];
                        break;
                    }
                }
                // std::cout << "lc = " << lc << " rc = " << rc << '\n';

                printf("%d\n", min(query_min(1, 1, lc - 1), query_min(1, rc + 1, n)));
            } else {
                printf("%d\n", query_min(1, in[a], out[a]));
            } 
        }
    }
}

标签:hson,int,节点,问题,cr,换根,out
From: https://www.cnblogs.com/Chronologika/p/17411400.html

相关文章

  • 使用ssm框架出现数据库连接问题
    java.sql.SQLException:Accessdeniedforuser'jdbc:mysql://localhost:3306/oa?useSSL=false&allo'@'localhost'(usingpassword:YES)或者是PublicKeyRetrievalisnotallowed查阅资料发现当publicKeyRetrievalisnotAllowed错误解决或依然会出现数据连接失败问......
  • 问题解一
    (1)用pycharm连接mysql时,需要安装一个驱动,点击连接界面,如果TestConnection不可用,点击右边的按钮即可(2)如果要将同一网站不同链接的数据存入数据库,可考虑重写start_requestseg:forindex,hrefinenumerate(self.start_urls):ifindex==0:yieldscrapy.Request(......
  • 僵尸进程问题解决
    1何为僵尸进程僵尸进程是当子进程比父进程先结束,而父进程又没有回收子进程,释放子进程占用的资源,此时子进程将成为一个僵尸进程。如果父进程先退出,子进程被init接管,子进程退出后init会回收其占用的相关资源。在UNIX系统中,一个进程结束了,但是它的父进程没有等待(调用wait/wai......
  • 填报志愿的基本问题
    1、什么是批次录取控制分数线?答:批次录取控制分数线又称省控线或批次线,是由省级招生考试机构根据当年全省考生高考成绩和招生计划,将全省考生分类别从高分到低分排序,综合各种因素后按一定比例分批次分别划定录取考生的最低投档分数标准。招生院校只能在本院校所在批次录取控制分数......
  • RK3588安装ROS 解决Rviz以及Gazebo报错问题
    RK3588安装ROS解决Rviz以及Gazebo报错问题InfoOperatingSystem&VersionUbuntu20.04KernelVersion(LinuxOnly)5.10.110PlatformROC-RK3588S-PC一、前言记录一下在RK3588上安装ubuntu20.04和ROS的过程,很早之前配置过,最近又重新配置了一遍,特此记录一......
  • ubuntu中使用vscode进行cuda c代码debug出现 no such file or directory 的问题
    {"version":"0.2.0","configurations":[{"name":"CUDAC++:Launch","type":"cuda-gdb","request":"launch","program":......
  • mysql按顺序递增(出现不连续问题)
    问题在表中添加新记录时,自动递增不连续(之前出现过了473,之后删除473,再插入新纪录,新纪录的id是474,我想让他的id为8)(用springboot+mybatis-plus插入新纪录)解决第一步1.如果是InnoDB引擎:将该字段先取消“自动递增”,去掉“不是null”的对勾,取消“主键”,并保存。如下图设置:第二......
  • 微服务使用openfeign调用单点的会话失效问题
    项目Springcloud,认证中心方式实现SSO使用开源框架Sa-Token本身的单独访问每个客户端服务的单点就没有问题。然后单点通过Fegin调用就不好使了!主要使用的Sa-Token的微服务单点功能使用的依赖如下<!--SA-TokenSSO--><dependencyManagement><dependencies>......
  • 对于office突然报错登录不上且修复不了的问题
    我可能是在清理启动项的时候把服务的启动项关闭了:具体操作如下:win+r输入services.msc打开服务列表接着找到将属性改为自动即可. ......
  • 工作中遇到的相关问题汇总
    VMware相关问题1、VMware混杂模式是一种网络模式,它允许虚拟机和物理机之间的网络流量相互通信。在混杂模式下,虚拟机可以接收和发送物理网络上的所有数据包,而不仅仅是发送给它们的数据包。这个模式通常用于测试和开发环境,因为它允许虚拟机与物理机之间进行更灵活的网络交互。但......