Aragorn's Story HDU - 3966 (树链剖分 + 模板)

版权声明:本文为博主瞎写的,请随便转载 https://blog.csdn.net/sdut_jk17_zhangming/article/details/86524650

题目 https://cn.vjudge.net/problem/HDU-3966

Fish_Li https://li-fish.github.io/2017/08/09/cjqx554pg002d4kc24xybxqqi/

树链剖分 https://www.cnblogs.com/George1994/p/7821357.html

题意

裸地树链剖分

思路

模板题

#include <bits/stdc++.h>

using namespace std;
#define lson o<<1
#define rson o<<1|1
#define MID int m = (l+r)/2

const int maxn =  50050;
const int INF = 0x3f3f3f3f;

struct Info {
    int sum, lazy, cnt;

    Info() {
        sum = lazy = cnt = 0;
    }

    Info operator+(const Info &a) {
        Info rst;
        rst.sum = sum + a.sum;
        rst.cnt = cnt + a.cnt;
        return rst;
    }
} tree[maxn << 2];

int n,m,p;
vector<int> edge[maxn];
int son[maxn],top[maxn],tid[maxn]; //重儿子 顶端节点 节点新编号
int siz[maxn],deep[maxn],fa[maxn]; //子树的节点数 深度 父亲节点
int data[maxn];  //节点权值
int id_data[maxn];
int _cnt; //节点编号

void build(int o, int l, int r)
{
    tree[o].lazy = 0;
    if(l == r)
    {
        tree[o].sum = id_data[l];
        tree[o].cnt = 1;
        return ;
    }
    MID;
    build(lson, l, m);
    build(rson, m + 1, r);
    tree[o] = tree[lson] + tree[rson];
}

void push_down(int o)
{
    if(!tree[o].lazy ) return ;
    int lazy = tree[o].lazy;
    tree[lson].lazy += lazy; //+= += ++
    tree[rson].lazy += lazy;
    tree[lson].sum += lazy * tree[lson].cnt;
    tree[rson].sum += lazy * tree[rson].cnt;
    tree[o].lazy = 0;
}

void updata(int o, int l, int r, int ul, int ur, int d) //当前节点 当前区间 改动区间
{
    if(r < ul || ur < l) return ;
    if(ul <= l && r <= ur)
    {
        tree[o].sum += tree[o].cnt * d;
        tree[o].lazy += d;
        return ;
    }
    push_down(o);
    MID;
    updata(lson, l, m, ul, ur, d);
    updata(rson, m + 1, r, ul, ur, d);
    tree[o] = tree[lson] + tree[rson];
}

Info query(int o, int l, int r, int pos)
{
    if (r < pos || pos < l) return Info();
    if(l == r)
    {
        return tree[o];
    }
    push_down(o);
    MID;
    return query(lson, l, m, pos) + query(rson, m + 1, r, pos);
}
void dffs(int u, int f, int d) //点 父节点 深度
{
    siz[u] = 1,deep[u] = d;
    fa[u] = f,son[u] = -1;
    for(int i = 0; i < edge[u].size(); i++)
    {
        int v = edge[u][i];
        if(v != f) //除去父节点
        {
            dffs(v, u, d + 1);
            siz[u] += siz[v];
            if(son[u] == -1||siz[son[u]] < siz[v]) //找重儿子
            {
                son[u] = v;
            }
        }
    }
}
void dfss(int u,int t)
{
    top[u] = t,tid[u] = _cnt++;
    id_data[_cnt - 1] = data[u]; //重新标号的数组
    if(son[u] != -1) dfss(son[u], t); //重儿子
    for(int i = 0; i<edge[u].size(); i++)
    {
        int v = edge[u][i];
        if(son[u] != v && fa[u] != v) dfss(v,v); //轻儿子
    }
}

void Updata(int x, int y, int d)
{
    int tx = top[x],ty = top[y]; //tx ty 为x y的链上的顶端节点
    while(tx != ty) //不同链
    {
        if(deep[tx] < deep[ty])
        {
            swap(x,y),swap(tx,ty); //让x为低的节点
        }
        updata(1, 1, n, tid[tx], tid[x], d); //链对应线段树改变
        x =  fa[tx], tx = top[x]; //x变为顶端节点父亲
    }
    if(deep[x] < deep[y]) swap(x, y); //同链
    updata(1, 1, n, tid[y], tid[x], d);
}

void splite()
{
    _cnt = 1;
    dffs(1, -1, 0);//找重儿子 点信息
    dfss(1, 1); //剖分 (求顶端节点,新编号)
}

void init()
{
    for(int i = 1;i <= n;i++)
    {
        scanf("%d",&data[i]);
        edge[i].clear();
    }
    for(int i = 1;i < n;i++)
    {
        int u,v;
        scanf("%d %d", &u, &v);
        edge[u].push_back(v);
        edge[v].push_back(u);
    }
}
void solve()
{
    splite();//树链剖分
    build(1, 1, n);
    char str[10];
    while(p--)
    {
        int a, b, c;
        scanf("%s",str);
        if(str[0] == 'Q')
        {
            scanf("%d",&a);
            printf("%d\n",query(1,1,n,tid[a]).sum);
        }
        else
        {
            scanf("%d %d %d", &a, &b, &c);
            if(str[0] == 'I')
            {
                Updata(a, b, c); //先进行树上链的查找
            }
            else
            {
                Updata(a, b, -c);
            }
        }
    }
}

int main()
{
    while(~scanf("%d %d %d", &n, &m, &p))
    {
        init();
        solve();
    }
}

猜你喜欢

转载自blog.csdn.net/sdut_jk17_zhangming/article/details/86524650