树链剖分

来源:互联网 发布:js怎么取整数 编辑:程序博客网 时间:2024/05/16 13:06

ACM模版

点权

参考题目链接:
HDU 3966 Aragorn’s Story

/* *  基于点权,查询单点值,修改路径的上的点权 */const int MAXN = 50010;struct Edge{    int to, next;} edge[MAXN * 2];int head[MAXN], tot;int top[MAXN];  //  top[v]表示v所在的重链的顶端节点int fa[MAXN];   //  父亲节点int deep[MAXN]; //  深度int num[MAXN];  //  num[v]表示以v为根的子树的节点数int p[MAXN];    //  p[v]表示v对应的位置int fp[MAXN];   //  fp和p数组相反int son[MAXN];  //  重儿子int pos;void init(){    tot = 0;    memset(head, -1, sizeof(head));    pos = 1;    //  使用树状数组,编号从头1开始    memset(son, -1, sizeof(son));    return ;}void addedge(int u, int v){    edge[tot].to = v;    edge[tot].next = head[u];    head[u] = tot++;    return ;}void dfs1(int u, int pre, int d){    deep[u] = d;    fa[u] = pre;    num[u] = 1;    for (int i = head[u]; i != -1; i = edge[i].next)    {        int v = edge[i].to;        if (v != pre)        {            dfs1(v, u, d + 1);            num[u] += num[v];            if (son[u] == -1 || num[v] > num[son[u]])            {                son[u] = v;            }        }    }    return ;}void getpos(int u, int sp){    top[u] = sp;    p[u] = pos++;    fp[p[u]] = u;    if (son[u] == -1)    {        return ;    }    getpos(son[u], sp);    for (int i = head[u]; i != -1; i = edge[i].next)    {        int v = edge[i].to;        if (v != son[u] && v != fa[u])        {            getpos(v, v);        }    }    return ;}//树状数组int lowbit(int x){    return x & (-x);}int c[MAXN];int n;int sum(int i){    int s = 0;    while (i > 0)    {        s += c[i];        i -= lowbit(i);    }    return s;}void add(int i, int val){    while (i <= n)    {        c[i] += val;        i += lowbit(i);    }    return ;}void Change(int u, int v, int val)  //  u->v的路径上点的值改变val{    int f1 = top[u], f2 = top[v];    while (f1 != f2)    {        if (deep[f1] < deep[f2])        {            swap(f1, f2);            swap(u, v);        }        add(p[f1], val);        add(p[u] + 1, -val);        u = fa[f1];        f1 = top[u];    }    if (deep[u] > deep[v])    {        swap(u, v);    }    add(p[u], val);    add(p[v] + 1, -val);    return ;}int a[MAXN];int main(){    int M, P;    while (scanf("%d%d%d", &n, &M, &P) == 3)    {        int u, v;        int C1, C2, K;        char op[10];        init();        for (int i = 1; i <= n; i++)        {            scanf("%d", &a[i]);        }        while(M--)        {            scanf("%d%d", &u, &v);            addedge(u, v);            addedge(v, u);        }        dfs1(1, 0, 0);        getpos(1, 1);        memset(c, 0, sizeof(c));        for (int i = 1; i <= n; i++)        {            add(p[i],a[i]);            add(p[i] + 1, -a[i]);        }        while (P--)        {            scanf("%s", op);            if (op[0] == 'Q')            {                scanf("%d", &u);                printf("%d\n", sum(p[u]));            }            else            {                scanf("%d%d%d", &C1, &C2, &K);                if (op[0] == 'D')                {                    K = -K;                }                Change(C1, C2, K);            }        }    }    return 0;}

边权

/* *  基于边权,修改单条边权,查询路径边权最大值 */const int MAXN = 10010;struct Edge{    int to, next;} edge[MAXN * 2];int head[MAXN], tot;int top[MAXN];  //  top[v]表示v所在的重链的顶端节点int fa[MAXN];   //  父亲节点int deep[MAXN]; //  深度int num[MAXN];  //  num[v]表示以v为根的子树的节点数int p[MAXN];    //  p[v]表示v与其父亲节点的连边在线段树中的位置int fp[MAXN];   //  和p数组相反int son[MAXN];  //  重儿子int pos;void init(){    tot = 0;    memset(head, -1, sizeof(head));    pos = 0;    memset(son, -1, sizeof(son));    return ;}void addedge(int u, int v){    edge[tot].to = v;    edge[tot].next = head[u];    head[u] = tot++;    return ;}void dfs1(int u, int pre, int d)    //  第一遍dfs求出fa,deep,num,son{    deep[u] = d;    fa[u] = pre;    num[u] = 1;    for (int i = head[u]; i != -1; i = edge[i].next)    {        int v = edge[i].to;        if (v != pre)        {            dfs1(v, u, d + 1);            num[u] += num[v];            if (son[u] == -1 || num[v] > num[son[u]])            {                son[u] = v;            }        }    }}void getpos(int u,int sp)   //  第二遍dfs求出top和p{    top[u] = sp;    p[u] = pos++;    fp[p[u]] = u;    if (son[u] == -1)    {        return ;    }    getpos(son[u], sp);    for (int i = head[u]; i != -1; i = edge[i].next)    {        int v = edge[i].to;        if (v != son[u] && v != fa[u])        {            getpos(v,v);        }    }    return ;}//  线段树struct Node{    int l, r;    int Max;} segTree[MAXN * 3];void build(int i, int l, int r){    segTree[i].l = l;    segTree[i].r = r;    segTree[i].Max = 0;    if (l == r)    {        return ;    }    int mid = (l + r) / 2;    build(i << 1, l, mid);    build((i << 1) | 1, mid + 1, r);    return ;}void push_up(int i){    segTree[i].Max = max(segTree[i << 1].Max, segTree[(i << 1)|1].Max);}void update(int i, int k, int val)  //  更新线段树的第k个值为val{    if (segTree[i].l == k && segTree[i].r == k)    {        segTree[i].Max = val;        return ;    }    int mid = (segTree[i].l + segTree[i].r) / 2;    if (k <= mid)    {        update(i << 1, k, val);    }    else    {        update((i << 1) | 1, k, val);    }    push_up(i);    return ;}int query(int i, int l, int r)  //  查询线段树中[l,r]的最大值{    if (segTree[i].l == l && segTree[i].r == r)    {        return segTree[i].Max;    }    int mid = (segTree[i].l + segTree[i].r) / 2;    if (r <= mid)    {        return query(i << 1, l, r);    }    else if (l > mid)    {        return query((i << 1) | 1, l, r);    }    else    {        return max(query(i << 1, l, mid), query((i << 1) | 1, mid + 1, r));    }}int find(int u,int v)   //  查询u->v边的最大值{    int f1 = top[u], f2 = top[v];    int tmp = 0;    while (f1 != f2)    {        if (deep[f1] < deep[f2])        {            swap(f1, f2);            swap(u, v);        }        tmp = max(tmp, query(1, p[f1], p[u]));        u = fa[f1];        f1 = top[u];    }    if (u == v)    {        return tmp;    }    if (deep[u] > deep[v])    {        swap(u, v);    }    return max(tmp, query(1, p[son[u]], p[v]));}int e[MAXN][3];int main(){    //  freopen("in.txt", "r", stdin);    //  freopen("out.txt", "w", stdout);    int T;    int n;    scanf("%d", &T);    while (T--)    {        init();        scanf("%d", &n);        for (int i = 0; i < n - 1; i++)        {            scanf("%d%d%d", &e[i][0], &e[i][1], &e[i][2]);            addedge(e[i][0], e[i][1]);            addedge(e[i][1], e[i][0]);        }        dfs1(1, 0, 0);        getpos(1, 1);        build(1, 0, pos - 1);        for (int i = 0; i < n-1; i++)        {            if (deep[e[i][0]] > deep[e[i][1]])            {                swap(e[i][0],e[i][1]);            }            update(1, p[e[i][1]], e[i][2]);        }        char op[10];        int u, v;        while (scanf("%s", op) == 1)        {            if (op[0] == 'D')            {                break;            }            scanf("%d%d", &u, &v);            if (op[0] == 'Q')            {                printf("%d\n", find(u, v));     //  查询u->v路径上边权的最大值            }            else            {                update(1, p[e[u - 1][1]], v);   //  修改第u条边的长度为v            }        }    }    return 0;}
0 0
原创粉丝点击