51Nod-1199-Money out of Thin Air

来源:互联网 发布:php 跨平台 编辑:程序博客网 时间:2024/05/21 08:51

ACM模版

描述

描述

题解

树链剖分 + 线段树搞搞,十分不错的一道题,折腾了好久才搞定……其实也不难,树链剖分算是一个比较简单的算法了,最起码好理解,两个 dfs 搞搞事情,获得一个树与链的映射关系即可,然后用这个链来进行线段树的相关处理。

代码

#include <cstdio>#include <cstring>#include <cctype>#include <algorithm>#define lson l, mid, x << 1#define rson mid + 1, r, x << 1 | 1#define ll long longusing namespace std;const int MAXN = 5e4 + 10;struct edge{    int to;    int nt;    edge()    {        nt = -1;    }};int tot = 0;int head[MAXN];edge eg[MAXN << 1];int read(){    int x = 0;    char c = getchar();    while (!isdigit(c))    {        c = getchar();    }    while (isdigit(c))    {        x = x * 10 + c - '0', c = getchar();    }    return x;}void add(int p, int pos){    eg[tot].to = pos;    eg[tot].nt = head[p];    head[p] = tot++;    eg[tot].to = p;    eg[tot].nt = head[pos];    head[pos] = tot++;}int N, M;int size[MAXN];int son[MAXN];int idx[MAXN];  //  idx[v] 表示 v 和其父节点的连边在线段树中的对应关系int id[MAXN];   //  id[v] 表示 v 在原树中的对应关系int w[MAXN];struct node{    ll sum;    ll add;};node tree[MAXN << 2];//  查找重边void dfsI(int x = 1, int pre = 0){    size[x] = 1;    for (int nt = head[x]; nt != -1; nt = eg[nt].nt)    {        if (eg[nt].to != pre)        {            dfsI(eg[nt].to, x);            size[x] += size[eg[nt].to];            if (!son[x] || size[eg[nt].to] > size[son[x]])            {                son[x] = eg[nt].to;            }        }    }}//  构造重链void dfsII(int x = 1){    id[++id[0]] = x;    idx[x] = id[0];    if (son[x])    {        dfsII(son[x]);    }    for (int nt = head[x]; nt != -1; nt = eg[nt].nt)    {        if (!idx[eg[nt].to])        {            dfsII(eg[nt].to);        }    }}void build(int l = 1, int r = N, int x = 1){    tree[x].add = -1;    if (l == r)    {        tree[x].sum = w[id[l]];        return ;    }    int mid = (l + r) >> 1;    build(lson);    build(rson);    tree[x].sum = tree[x << 1].sum + tree[x << 1 | 1].sum;}void pushdown(int x, int cnt){    if (tree[x].add != -1)    {        if (tree[x << 1].add != -1)        {            tree[x << 1].add += tree[x].add;        }        else        {            tree[x << 1].add = tree[x].add;        }        if (tree[x << 1 | 1].add != -1)        {            tree[x << 1 | 1].add += tree[x].add;        }        else        {            tree[x << 1 | 1].add = tree[x].add;        }        tree[x << 1].sum += tree[x].add * (cnt - (cnt >> 1));        tree[x << 1 | 1].sum += tree[x].add * (cnt >> 1);        tree[x].add = -1;    }}//  更新单结点void update1(int p, int add, int l, int r, int x){    if (l == r)    {        tree[x].sum += add;        return ;    }    pushdown(x, r - l + 1);    int mid = (l + r) >> 1;    p <= mid ? update1(p, add, lson) : update1(p, add, rson);    tree[x].sum = tree[x << 1].sum + tree[x << 1 | 1].sum;}void update2(int tl, int tr, int add, int l, int r, int x){    if (tl <= l && tr >= r)    {        if (tree[x].add != -1)        {            tree[x].add += add;        }        else        {            tree[x].add = add;        }        tree[x].sum += (ll)add * (r - l + 1);        return ;    }    pushdown(x, r - l + 1);    int mid = (l + r) >> 1;    if (tl <= mid)    {        update2(tl, tr, add, lson);    }    if (tr > mid)    {        update2(tl, tr, add, rson);    }    tree[x].sum = tree[x << 1].sum + tree[x << 1 | 1].sum;}ll query1(int p, int l, int r, int x){    if (l == r)    {        return tree[x].sum;    }    pushdown(x, r - l + 1);    int mid = (l + r) >> 1;    return p <= mid ? query1(p, lson) : query1(p, rson);}ll query2(int tl, int tr, int l, int r, int x){    if (tl <= l && tr >= r)    {        return tree[x].sum;    }    pushdown(x, r - l + 1);    int mid = (l + r) >> 1;    ll ans = 0;    if (tl <= mid)    {        ans += query2(tl, tr, lson);    }    if (tr > mid)    {        ans += query2(tl, tr, rson);    }    return ans;}int main(){//    freopen("/Users/zyj/Desktop/input.txt", "r", stdin);    memset(head, -1, sizeof(head));    N = read();    M = read();    int p;    for (int i = 2; i <= N; i++)    {        p = read() + 1;        w[i] = read();        add(p, i);    }    dfsI();    dfsII();    build();    int x, y, z;    char s[3];    for (int i = 1; i <= M; i++)    {        scanf("%s", s);        x = read() + 1;        y = read();        z = read();        if (s[0] == 'S')        {            if (query1(idx[x], 1, N, 1) < y)            {                update1(idx[x], z, 1, N, 1);            }        }        else        {            ll sum = query2(idx[x], idx[x] + size[x] - 1, 1, N, 1);            if (sum >= (ll)y * size[x])            {                continue;            }            update2(idx[x], idx[x] + size[x] - 1, z, 1, N, 1);        }    }    for (int i = 1; i <= N; i++)    {        printf("%lld\n", query1(idx[i], 1, N, 1));    }    return 0;}

参考

《树链剖分》

0 0