1、题目大意:三个操作,换根,修改树上的某条路径,查询一个子树的最小值

2、分析:这个其实还是挺好做的,修改树上的某条路径,裸树剖,查询子树的最小值,这个是树剖满足dfs序

那么就是换根了,对吧,其实换根是o(1)的,就是root = u嘛。。。那么另两个操作就要变一变了,

那个修改路径是不变的,因为你不管怎么换根,树上的路径都是唯一的。。。这个结束

查询子树的最小值呢,分情况讨论,我分了三种 1.如果询问根,全询问,2.如果询问的是现在根的n辈祖先,

那么除了现在根的n-1辈祖先的那棵子树不询问以外,其余的都要查询3.否则就是原来的那棵子树

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
using namespace std;
#define M 1000000
struct tree_chain_partition{
    int Size[M], Top[M], Fa[M], value[M], num[M], Height[M], left[M], right[M];
    int n;
    int root;
    int son[M], head[M], Next[M];
    int tot, ST_tot;
    int q[M], lazy[M];
    int tt[M][30];
    void init(){
        memset(lazy, -1, sizeof(lazy));
        memset(head, -1, sizeof(head));
        tot = ST_tot = 0;
        Top[1] = 1;
    }
    void pushdown(int o){
        if(lazy[o] != -1){
            q[2 * o] = q[2 * o + 1] = lazy[2 * o] = lazy[2 * o + 1] = lazy[o];
            lazy[o] = -1;
        }
    }
    void add(int l, int r, int o, int x, int y, int k){
        if(x <= l && r <= y){
            q[o] = k;
            lazy[o] = k;
            return;
        }
        pushdown(o);
        int mid = (l + r) / 2;
        if(x <= mid) add(l, mid, 2 * o, x, y, k);
        if(y > mid) add(mid + 1, r, 2 * o + 1, x, y, k);
        q[o] = min(q[2 * o + 1], q[2 * o]);
    }
    int query(int l, int r, int o, int x, int y){
        if(x > y) return 2147483647;
        if(x <= l && r <= y) return q[o];
        pushdown(o);
        int mid = (l + r) / 2;
        int ret = 2147483647;
        if(x <= mid) ret = min(ret, query(l, mid, 2 * o, x, y));
        if(y > mid) ret = min(ret, query(mid + 1, r, 2 * o + 1, x, y));
        return ret;
    }
    inline void insert(int x, int y){
        tot ++;
        son[tot] = y;
        Next[tot] = head[x];
        head[x] = tot;
    }
    void dfs1(int x, int fa, int height){
        Height[x] = height;
        Fa[x] = fa;
        for(int i = head[x]; i != -1; i = Next[i]) if(son[i] != fa){
            dfs1(son[i], x, height + 1);
            Size[x] += Size[son[i]];
        }
        Size[x] ++;
    }
    void dfs2(int x, int fa){
        ST_tot ++;
        add(1, n, 1, ST_tot, ST_tot, value[x]);
        num[x] = ST_tot;
        left[x] = ST_tot;
        int o = 0, ss = 0;
        for(int i = head[x]; i != -1; i = Next[i]) if(son[i] != fa){
            if(Size[son[i]] > ss){
                o = i;
                ss = Size[son[i]];
            }
        }
        if(o != 0){
            Top[son[o]] = Top[x];
            dfs2(son[o], x);
        }
        for(int i = head[x]; i != -1; i = Next[i]) if(o != i && son[i] != fa){
            Top[son[i]] = son[i];
            dfs2(son[i], x);
        }
        right[x] = ST_tot;
    }
    void init_lca(){
        for(int i = 1; i <= n; i ++) tt[i][0] = Fa[i];
        for(int i = 1; i <= 20; i ++){
            for(int j = 1; j <= n; j ++){
                tt[j][i] = tt[tt[j][i - 1]][i - 1];
            }
        }
    }
    int zux(int x, int k){
        for(int i = 0; i <= 20; i ++) if((1 << i) & k){
            x = tt[x][i];
        }
        return x;
    }
    bool is_(int x, int y){
        if(Height[x] >= Height[y]) return false;
        if(zux(y, Height[y] - Height[x]) == x) return true;
        return false;
    }
    void add_root(int o){
        root = o;
    }
    void real_add(int x, int y, int v){
        while(Top[x] != Top[y]){
            if(Height[Top[x]] < Height[Top[y]]) swap(x, y);
            add(1, n, 1, num[Top[x]], num[x], v);
            x = Fa[Top[x]];
        }
        if(Height[x] < Height[y]) swap(x, y);
        add(1, n, 1, num[y], num[x], v);
    }
    int real_query(int x){
        if(x == root){
            return query(1, n, 1, left[1], right[1]);
        }
        else if(is_(x, root)){
            int qt = zux(root, Height[root] - Height[x] - 1);
            return min(query(1, n, 1, left[1], left[qt] - 1), query(1, n, 1, right[qt] + 1, right[1]));
        }
        else{
            return query(1, n, 1, left[x], right[x]);
        }
    }
} wt;
int main(){
    int n, m;
    scanf("%d%d", &n, &m);
    wt.n = n;
    wt.init();
    for(int i = 1; i < n; i ++){
        int x, y;
        scanf("%d%d", &x, &y);
        wt.insert(x, y);
        wt.insert(y, x);
    }
    for(int i = 1; i <= n; i ++){
        scanf("%d", &wt.value[i]);
    }
    scanf("%d", &wt.root);
    wt.dfs1(1, 0, 1);
    wt.dfs2(1, 0);
    wt.init_lca();
    for(int i = 1; i <= m; i ++){
        int op, x, y, z;
        scanf("%d", &op);
        if(op == 1){
            scanf("%d", &x);
            wt.add_root(x);
        }
        else if(op == 2){
            scanf("%d%d%d", &x, &y, &z);
            wt.real_add(x, y, z);
        }
        else{
            scanf("%d", &x);
            printf("%d\n", wt.real_query(x));
        }
    }
    return 0;
}

BZOJ3083——遥远的国度的更多相关文章

  1. BZOJ3083 遥远的国度 【树链剖分】

    BZOJ3083 遥远的国度 Description zcwwzdjn在追杀十分sb的zhx,而zhx逃入了一个遥远的国度.当zcwwzdjn准备进入遥远的国度继续追杀时,守护神RapiD阻拦了zcw ...

  2. bzoj3083 遥远的国度 &amp;&amp; bzoj3626 LCA (树链剖分)

    今早刷了两道树剖的题目,用时两小时十五分钟= = 树剖的题目代码量普遍120+ 其实打熟练之后是很容易调的,不熟练的话代码量大可能会因为某些小细节调很久 3083:裸树剖+"换根" ...

  3. [luogu3979][bzoj3083]遥远的国度

    [luogu传送门] [bzoj传送门] 题目描述 zcwwzdjn在追杀十分sb的zhx,而zhx逃入了一个遥远的国度.当zcwwzdjn准备进入遥远的国度继续追杀时,守护神RapiD阻拦了zcww ...

  4. 2018.06.30 BZOJ3083: 遥远的国度(换根树剖)

    3083: 遥远的国度 Time Limit: 10 Sec Memory Limit: 512 MB Description 描述 zcwwzdjn在追杀十分sb的zhx,而zhx逃入了一个遥远的国 ...

  5. BZOJ3083 遥远的国度(树链剖分+线段树)

    考虑暴力树剖.那么修改路径和查询子树最小值非常简单. 对于换根当然不能真的给他转一下,我们只记录当前根是哪个.对于查询,如果查询点不在当前根到原根的路径上,显然换根是对答案没有影响的:如果是当前根,答 ...

  6. 【树链剖分】【线段树】bzoj3083 遥远的国度

    记最开始的根为root,换根之后,对于当前的根rtnow和询问子树U而言, ①rtnow==U,询问整棵树 ②fa[rtnow]==U,询问除了rtnow所在子树以外的整棵树 ③rtnow在U的子树里 ...

  7. BZOJ3083 遥远的国度 【树剖】

    题目 zcwwzdjn在追杀十分sb的zhx,而zhx逃入了一个遥远的国度.当zcwwzdjn准备进入遥远的国度继续追杀时,守护神RapiD阻拦了zcwwzdjn的去路,他需要zcwwzdjn完成任务 ...

  8. BZOJ3083: 遥远的国度

    传送门 BZOJ100题辣(已经无法直视的正确率 树剖板子题,注意和dfs序结合,根据根的变化变换统计的方式即可. //BZOJ 3083 //by Cydiater //2016.10.23 #in ...

  9. bzoj3083 遥远的国度 题解

    题目大意: 给定一棵有根树,每个点有一个权值,提供三种操作: 1.将x节点变为根节点 2.将x到y路径上的点的权值全部改为v 3.询问x的子树中点权的最小值 思路: 用DFS序剖分,记录每个节点入栈出 ...

随机推荐

  1. h5调用摄像头

    <!DOCTYPE html><html lang="zh-CN"><head> <meta charset="UTF-8&qu ...

  2. Smarty 配置文件的读取

    http://www.cnblogs.com/gbyukg/archive/2012/06/12/2539067.html

  3. 5-2-2 printf参数从右往左压栈

    5-2-2 C中printf计算参数时是从右到左压栈的 #include <stdio.h> int main (int argc, char **argv) { ; ,,,,}; int ...

  4. BZOJ 1076 奖励关

    注意几点: 1.为什么要逆推?由此状态可以轻易算出彼状态是否可行,而彼状态却无法轻易还原为此状态. 2.为什么可以逆推?假设时光倒流了....23333 3.注意位运算的准确,大胆写方程. #incl ...

  5. x/nfu-用gdb查看内存

    用gdb查看内存 2007-12-08 12:43 用gdb查看内存 格式: x /nfu <addr> 说明x 是 examine 的缩写 n表示要显示的内存单元的个数 f表示显示方式, ...

  6. 【Eclipse】web项目部署新手篇

    本文属于新手篇章,记录了Eclipse中部署web项目的步骤 1 . 添加Tomcat服务器 右键项目属性-->Run as-->Run on server弹出以下界面 点击finish之 ...

  7. Django基础三(form和template)

    上一篇博文学习了Django的View和urls,接下来是对django form 和 template的学习. 1 django form django form为我们提供了便捷的方式来创建一些HT ...

  8. Codeforces 1120 简要题解

    文章目录 A题 B题 C题 D题 E题 F题 传送门 A题 传送门 题意简述:给你一个mmm个数的数列,现在规定把一个数列的1,2,...,k1,2,...,k1,2,...,k分成第一组,把k+1, ...

  9. C++类相关

    本文打算通过一些小例子来说明几个关键的知识点. 一:成员函数相关 #include <iostream> using namespace std; class D { public: vo ...

  10. python学习之老男孩python全栈第九期_day001作业

    1.使用while循环输入 1 2 3 4 5 6     8 9 10 count = 0 while count <= 9: count += 1 if count == 7:continu ...