[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\n" , 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\n" , min(SGT.query(1 , 1 , l[y] - 1) , SGT.query(1 , r[y] + 1 , n)));
                        } else printf("%d\n" , SGT.query(1 , l[x] , r[x]));
                }
        }
        
        return 0;
    
}

猜你喜欢

转载自www.cnblogs.com/evenbao/p/10054393.html