• [BZOJ 3306] 树


    [题目链接]

             https://www.lydsy.com/JudgeOnline/problem.php?id=3306

    [算法]

             若没有换根操作 , 那么“查询子树最小值”就可以用DFS序 + 线段树解决

             进一步地 , 可以发现换根后 , 造成影响的点在原根到新根的路径上 , 根据这个性质 , 问题得到解决

             时间复杂度 : O(NlogN)

    [代码]

            

    #include<bits/stdc++.h>
    using namespace std;
    #define MAXN 100010
    #define MAXLOG 20
    const int inf = 2e9;
    typedef long long ll;
    typedef long double ld;
    
    struct edge
    {
            int to , nxt;
    } e[MAXN << 2];
    
    int n , q , rt , timer , tot;
    int dfn[MAXN] , l[MAXN] , r[MAXN] , value[MAXN] , loc[MAXN] , head[MAXN] , depth[MAXN];
    int up[MAXN][MAXLOG];
    
    struct Segment_Tree
    {
            struct Node
            {
                    int l , r;
                    int Min;    
            }    Tree[MAXN << 2];
            inline void update(int index)
            {
                    Tree[index].Min = min(Tree[index << 1].Min , Tree[index << 1 | 1].Min);
            }
            inline void build(int index , int l , int r)
            {
                    Tree[index].l = l;
                    Tree[index].r = r;
                    if (l == r)
                    {
                            Tree[index].Min = value[loc[l]];
                            return;
                    }
                    int mid = (l + r) >> 1;
                    build(index << 1 , l , mid);
                    build(index << 1 | 1 , mid + 1 , r);
                    update(index);
            }
            inline void modify(int index , int pos , int v)
            {
                    if (Tree[index].l == Tree[index].r)
                    {
                            Tree[index].Min = v;
                            return;
                    }
                    int mid = (Tree[index].l + Tree[index].r) >> 1;
                    if (mid >= pos) modify(index << 1 , pos , v);
                    else modify(index << 1 | 1 , pos , v);
                    update(index);
            }
            inline int query(int index , int l , int r)
            {
                    if (l > r) return inf;
                    if (Tree[index].l == l && Tree[index].r == r)
                            return Tree[index].Min;
                    int mid = (Tree[index].l + Tree[index].r) >> 1;
                    if (mid >= r) return query(index << 1 , l , r);
                    else if (mid + 1 <= l) return query(index << 1 | 1 , l , r);
                    else return min(query(index << 1 , l , mid) , query(index << 1 | 1 , mid + 1 , r));
            }
            inline int query()
            {
                    return Tree[1].Min;
            }
    } SGT;
    
    template <typename T> inline void chkmax(T &x,T y) { x = max(x,y); }
    template <typename T> inline void chkmin(T &x,T y) { x = min(x,y); }
    template <typename T> inline void read(T &x)
    {
        T f = 1; x = 0;
        char c = getchar();
        for (; !isdigit(c); c = getchar()) if (c == '-') f = -f;
        for (; isdigit(c); c = getchar()) x = (x << 3) + (x << 1) + c - '0';
        x *= f;
    }
    inline void addedge(int u , int v)
    {
            ++tot;
            e[tot] = (edge){v , head[u]};
            head[u] = tot;
    }
    inline void dfs(int u , int father)
    {
            depth[u] = depth[father] + 1;
            dfn[u] = l[u] = ++timer;
            loc[timer] = u;
            up[u][0] = father;
            for (int i = 1; i < MAXLOG; i++) up[u][i] = up[up[u][i - 1]][i - 1];
            for (int i = head[u]; i; i = e[i].nxt)
            {
                    int v = e[i].to;
                    if (v == father) continue;
                    dfs(v , u);        
            }        
            r[u] = timer;
    }
    
    int main()
    {
            
            scanf("%d%d" , &n , &q);
            for (int i = 1; i <= n; i++)
            {
                    int f;
                    scanf("%d%d" , &f , &value[i]);
                    if (f > 0) addedge(f , i);        
                    else rt = i;        
            } 
            dfs(rt , 0);
            SGT.build(1 , 1 , n);
            while (q--)
            {
                    char type[5];
                    scanf("%s" , &type);
                    if (type[0] == 'V')
                    {
                            int x , y;
                            scanf("%d%d" , &x , &y);
                            SGT.modify(1 , dfn[x] , y);
                    } else if (type[0] == 'E')
                    {
                            int x;
                            scanf("%d" , &x);
                            rt = x;
                    } else
                    {
                            int x;
                            scanf("%d" , &x);
                            if (x == rt) printf("%d
    " , SGT.query());
                            else if (l[x] <= l[rt] && r[x] >= r[rt])
                            {
                                    int y = rt;
                                    for (int i = MAXLOG - 1; i >= 0; i--)
                                    {
                                            if (depth[up[y][i]] > depth[x])
                                                    y = up[y][i];
                                    }
                                    printf("%d
    " , min(SGT.query(1 , 1 , l[y] - 1) , SGT.query(1 , r[y] + 1 , n)));
                            } else printf("%d
    " , SGT.query(1 , l[x] , r[x]));
                    }
            }
            
            return 0;
        
    }
  • 相关阅读:
    Linux并发与同步专题 (1)原子操作和内存屏障
    Linux并发与同步专题
    功耗案例分析:周期性底电流抬高问题分析和解决
    Android OpenGL 基础入门
    使用Codeblock搭建Windows下Objec-c学习环境
    Muduo 多线程模型对比
    NPTL 线程同步方式
    C++ 封装互斥对象
    Java 常用字符串操作总结
    Android 开发有用代码积累
  • 原文地址:https://www.cnblogs.com/evenbao/p/10054393.html
Copyright © 2020-2023  润新知