洛谷P3178[HAOI]2015 树上操作

题目

树剖裸题,这个题更可以深刻的理解树剖中把树上的节点转换为区间的思想。

要注意在区间上连续的节点,一定是在一棵子树中。

#include <bits/stdc++.h>
#define int long long 
#define ls left, mid, root << 1
#define rs mid + 1, right, root << 1 | 1
#define N 600100    
using namespace std;
int n, m, rot, mod, tot, cnt;   
int data[N], id[N], dep[N], size[N], lin[N], ans[N * 8], lazy[N * 8], dp[N], fa[N], top[N], son[N];
struct edg {
    int to, nex;
} e[N];
inline void add(int f, int t)
{
    e[++cnt].to = t;
    e[cnt].nex = lin[f];
    lin[f] = cnt;
}           
inline void pushup(int root)
{
    ans[root] = (ans[root << 1] + ans[root << 1 | 1]);
}    
inline void pushdown(int root, int left, int right)
{ 
    int mid = (left + right) >> 1;
    if (lazy[root])
    {
        ans[root << 1] += (mid - left + 1) * lazy[root];
        ans[root << 1];
        ans[root << 1 | 1] += (right - mid) * lazy[root];
        ans[root << 1 | 1];
        lazy[root << 1] += lazy[root]; 
        lazy[root << 1 | 1] += lazy[root];
        lazy[root] = 0; 
    }
}
void build(int left, int right, int root)
{
    if (left == right)
    {   
        ans[root] = dp[left], ans[root];
        return;     
    }               
    int mid = (left + right) >> 1;
    build(ls), build(rs);
    pushup(root);   
}                   
inline void update(int left, int right, int root, int add, int ql, int qr)
{   
    if (left >= ql && right <= qr)
    {
        ans[root] += (right - left + 1) * add;
        lazy[root] += add;     
        ans[root];
        return;                
    }                          
    int mid = (left + right) >> 1;
    pushdown(root, left, right);//线段树的pushdown操作是为了弥补之前没向下传递标记的坑。 
    if (ql <= mid)              
        update(ls, add, ql, qr);
    if (qr > mid)               
        update(rs, add, ql, qr);
    pushup(root);               
}   
inline int query(int left, int right, int root, int ql, int qr)
{
    int res = 0;
    if (left >= ql && right <= qr)
        return ans[root];
    int mid = (left + right) >> 1;
    pushdown(root, left, right);
    if (ql <= mid)
        res = ( res + query(ls, ql, qr) );
    if (qr > mid)
        res = res + query(rs, ql, qr) ;
    return res;
}
void dfs1(int now, int f, int de)
{   
    fa[now] = f, dep[now] = de, size[now] = 1;
    int maxsize = -1;
    for (int i = lin[now]; i; i = e[i].nex)
    {
        if (e[i].to == f) continue;
        dfs1(e[i].to, now, de + 1);
        size[now] += size[e[i].to];
        if (size[e[i].to] > maxsize)
        {
            maxsize = size[e[i].to];
            son[now] = e[i].to;
        }
    }
}   
void ulca(int x, int y, int z)
{
    while (top[x] != top[y])
    {
        if (dep[top[x]] < dep[top[y]])
            swap(x, y);
        update(1, n, 1, z, id[top[x]], id[x]);
        x = fa[top[x]];
    }
    if (dep[x] > dep[y])
        swap(x, y);
    update(1, n, 1, z, id[x], id[y]); 
}
int qlca(int x, int y)
{
    int res = 0;
    while (top[x] != top[y])
    {
        if (dep[top[x]] < dep[top[y]])
            swap(x, y);
        res = ( res + query(1, n, 1, id[top[x]], id[x]) );
        x = fa[top[x]];
    }
    if (dep[x] > dep[y])
        swap(x, y);
    res = ( res + query(1, n, 1, id[x], id[y]) );
    return res;
}
void upd(int x, int y) 
{
    update(1, n, 1, y, id[x], id[x] + size[x] - 1);
}
int que(int x) 
{
    return query(1, n, 1, id[x], id[x] + size[x] - 1);
}
void dfs2(int now, int t)
{
    top[now] = t;
    dp[++tot] = data[now];
    id[now] = tot;
    if (!son[now])
        return;
    dfs2(son[now], t);
    for (int i = lin[now]; i; i = e[i].nex)
    {
        int to = e[i].to;
        if (to != fa[now] && to != son[now])
            dfs2(to, to);
    }
}
signed main()
{
    scanf("%lld%lld", &n, &m);
    rot = 1;
    for (int i = 1; i <= n; i++)
            scanf("%lld", &data[i]); 
    for (int i = 1; i < n; i++)
    {
        int a, b;
        scanf("%lld%lld", &a, &b);
        add(a, b);
        add(b, a);
    }
    dfs1(rot, 0, 1);
    dfs2(rot, rot);
    build(1, n, 1); 
    for (int i = 1; i <= m; i++)
    {   
        int flag;
        scanf("%lld", &flag);
        if (flag == 1)
        {
            int x, a;
            scanf("%lld%lld", &x, &a);
            update(1, n, 1, a, id[x], id[x]);
        }
        if (flag == 2)
        {
            int x, a;
            scanf("%lld%lld", &x, &a);
            update(1, n, 1, a, id[x],  id[x] + size[x] - 1);
        }
        if (flag == 3)
        {
            int a;
            scanf("%lld", &a);
            printf("%lld\n", qlca(1, a));//不能写成id[1],id[a]因为id子树之间是连续的,所以a到1之间并不是连续边号。 
        }
    }   
    return 0;
}
/*
5 5 2 24
7 3 7 8 0 
1 2
1 5
3 1
4 1
3 4 2
3 2 2
4 5
1 5 1 3
2 1 3
*/

猜你喜欢

转载自www.cnblogs.com/liuwenyao/p/11229609.html