HDU 3966 Aragorn's Story 树链剖分模板

题目:http://acm.hdu.edu.cn/showproblem.php?pid=3966

题解:

#include
#include
#include
#include
using namespace std;

#define MAXN 50010
#define L(u) (u<<1)
#define R(u) (u<<1|1)

//写在类里面爆栈
int n, m, q;
int tim;       //时间戳
int num[MAXN]; //树上每个节点的初始值
int siz[MAXN]; //siz[u]表示以u为根的子树的节点数
int top[MAXN]; //树链上深度最小的点
int son[MAXN]; //重儿子
int dep[MAXN]; //深度
int tid[MAXN]; //节点的时间戳
int _tid[MAXN]; //tid[i]=j表示时间戳为i的节点是j
int father[MAXN]; //父节点
bool vis[MAXN];
vector edge[MAXN];

void init(int n)
{
    for(int i = 1; i <= n; i++)
    {
        siz[i] = top[i] = son[i] = 0;
        dep[i] = tid[i] = _tid[i] = father[i] = 0;
        vis[i] = false;
        tim = 0; //时间戳
        edge[i].clear();
    }
}

void addedge(int u, int v) //无根树加双向边
{
    edge[u].push_back(v);
    edge[v].push_back(u);
}

//树链剖分
void dfs1(int u, int pre)
{
    vis[u] = true;
    siz[u] = 1;
    father[u] = pre;
    dep[u] = dep[pre] + 1; //注意根节点比较特殊
    int sz = edge[u].size();
    for(int i = 0; i < sz; i++)
    {
        int v = edge[u][i];
        if(v != father[u] && vis[v] == false)
        {
            dfs1(v, u);
            siz[u] += siz[v];
            if(son[u] == 0) son[u] = v;
            else if(siz[son[u]] < siz[v]) son[u] = v;
        }
    }
}

void dfs2(int u, int tp)
{
    vis[u] = true;
    tid[u] = ++tim;
    _tid[tim] = u;
    top[u] = tp;
    if(son[u] != 0)
        dfs2(son[u], tp); //同一条重链的顶部相同

    int sz = edge[u].size();
    for(int i = 0; i < sz; i++)
    {
        int v = edge[u][i];
        if(v != father[u] && v != son[u] && vis[v] == false) //注意去掉重儿子
            dfs2(v, v);
    }
}

void update(int u, int l, int r, int v); //线段树的更新函数

void change(int x, int y, int val)
{
    while(top[x] != top[y])
    {
        if(dep[top[x]] < dep[top[y]])
            swap(x, y);
        update(1, tid[top[x]], tid[x], val); //dfs2时顶部先访问,故tid[top]较小
        x = father[top[x]]; //因为top[x]->x路径上的所有点已经被更新了
    }

    if(dep[x] > dep[y]) //同一条重链上深度小的tid小
        swap(x, y);
    update(1, tid[x], tid[y], val);
}


//线段树部分
struct NODE {
    int l, r, val, lazy;
}node[MAXN*4];

void build(int u, int l, int r)
{
    node[u].l = l;
    node[u].r = r;
    node[u].lazy = node[u].val = 0;
    if(l == r)
    {
        node[u].val = num[_tid[l]];
        return;
    }

    int mid = (l + r) >> 1;
    build(L(u), l, mid);
    build(R(u), mid + 1, r);
}

void pushdown(int u)
{
    if(node[u].lazy != 0)
    {
        node[L(u)].val += node[u].lazy;
        node[R(u)].val += node[u].lazy;
        node[L(u)].lazy += node[u].lazy;
        node[R(u)].lazy += node[u].lazy;
        node[u].lazy = 0;
    }
}

void update(int u, int l, int r, int v)
{
    if(node[u].l == l && node[u].r == r)
    {
        node[u].val += v;
        node[u].lazy += v;
        return;
    }

    pushdown(u);
    int mid = (node[u].l + node[u].r) >> 1;
    if(r <= mid)
        update(L(u), l, r, v);
    else if(l > mid)
        update(R(u), l, r, v);
    else
    {
        update(L(u), l, mid, v);
        update(R(u), mid + 1, r, v);
    }
}

int query(int u, int x)
{
    if(node[u].l == x && node[u].r == x)
        return node[u].val;

    pushdown(u);
    int mid = (node[u].l + node[u].r) >> 1;
    if(x <= mid) return query(L(u), x);
    else return query(R(u), x);
}


int main()
{
    char oper[2];
    int a, b, c;
    while(scanf("%d%d%d",&n,&m,&q) != EOF)
    {
        init(n);

        for(int i = 1; i <= n; i++)
            scanf("%d", &num[i]);

        for(int i = 1; i <= m; i++)
        {
            scanf("%d%d",&a, &b);
            addedge(a, b);
        }

        dfs1(1, 0);
        memset(vis, 0, sizeof(vis));
        dfs2(1, 1);
        build(1, 1, n);

        while(q--)
        {
            scanf("%s", oper);
            if(oper[0] == 'Q')
            {
                scanf("%d", &a);
                printf("%d\n", query(1, tid[a]));
            }
            else
            {
                scanf("%d%d%d", &a, &b, &c);
                if(oper[0] == 'I')
                    change(a, b, c);
                else
                    change(a, b, -c);
            }
        }
    }
    return 0;
}


你可能感兴趣的:(树链剖分)