您的位置:首页 > 编程语言 > Go语言

[HDU 3966] Aragorn's Story 树链剖分

2015-08-27 18:23 549 查看
http://acm.hdu.edu.cn/showproblem.php?pid=3966

题意:给一棵树,并给定各个点权的值,然后有3种操作:

I C1 C2 K : 把 C1 与 C2 的路径上的所有点权值加上 K

D C1 C2 K:把 C1 与 C2 的路径上的所有点权值减去 K

Q C:查询节点编号为C的权值

思路:树链剖分,先进行剖分,然后用线段树或 splay 去维护即可

注意:代码前面加上#pragma comment(linker, “/STACK:1024000000,1024000000”)调整栈的大小

[code]#pragma comment(linker, "/STACK:1024000000,1024000000")
#include <cstdio>
#include <cstring>
#include <iostream>

using namespace std;/

const int maxn = 50010;
const int inf = (1<<31)-1;

struct node{  //线段树结构体
    int l, r;
    int key,lazy;
};

struct side{ //树的结构体
    int to;
    int next;
};

int n,m,p,top;
int mapn[maxn];
int head[maxn];
side ed[maxn<<1];
node tr[maxn<<2];

int son[maxn], fa[maxn], siz[maxn]; //重儿子,父结点,以自己为根的子树的结点个数
int pre[maxn], deep[maxn], has[maxn], ran[maxn]; //树链的顶部,结点深度,在线段树中的位置,在线段对应树种编号

int add(int x, int y)  //建边
{
    ed[top].to = y;
    ed[top].next = head[x];
    head[x] = top++;
    return 0;
}

int Dfs_1(int rt, int d) //求出siz,  deep, fa,son;
{
    siz[rt] = 1;
    deep[rt] = d;
    for(int i = head[rt]; ~i ; i = ed[i].next){
        if(ed[i].to != fa[rt]){
            fa[ed[i].to] = rt;
            Dfs_1(ed[i].to, d+1);
            siz[rt] += siz[ed[i].to];
            if(son[rt] == -1 || siz[ed[i].to] > siz[son[rt]])
                son[rt] = ed[i].to;
        }
    }
    return 0;
}

int Dfs_2(int rt, int pr)//求出pre,has, ran;
{
    pre[rt] = pr;
    has[rt] = top++;
    ran[has[rt]] = rt;
    if(son[rt] == -1)
        return 0;
    Dfs_2(son[rt], pr);  //先遍历重链
    for(int i = head[rt]; ~i ; i = ed[i].next){
        if(ed[i].to != son[rt] && ed[i].to != fa[rt]){
            Dfs_2(ed[i].to, ed[i].to);
        }
    }
    return 0;
}

int Build(int rt, int l, int r) //构建线段树
{
    tr[rt].l = l;
    tr[rt].r = r;
    tr[rt].lazy = 0;
    if(l == r){
        tr[rt].key = mapn[ran[l]];
        return tr[rt].key;
    }
    int mid = (l+r)>>1;
    int sl = Build(rt<<1, l, mid);
    int sr = Build(rt<<1|1, mid+1, r);
    tr[rt].key = sl>sr?sl:sr;
    return tr[rt].key;
}

inline int push_down(int rt)
{
    if(tr[rt].lazy == 0)
        return 0;
    tr[rt<<1].key += tr[rt].lazy;
    tr[rt<<1].lazy += tr[rt].lazy;
    tr[rt<<1|1].key += tr[rt].lazy;
    tr[rt<<1|1].lazy += tr[rt].lazy;
    tr[rt].lazy = 0;
    return 0;
}

int Updata(int rt, int l, int r, int key)  //更新线段树
{
    if(tr[rt].r < l||tr[rt].l > r)
        return 0;
    if(l <= tr[rt].l && tr[rt].r <= r){
        tr[rt].key += key;
        tr[rt].lazy += key;
        return 0;
    }
    push_down(rt);
    Updata(rt<<1, l, r, key);
    Updata(rt<<1|1, l, r, key);
    return 0;
}

int Query(int rt,int l,int r)  //线段树上查询
{
    if(tr[rt].r < l||tr[rt].l > r)
        return -inf;
    if(l <= tr[rt].l && tr[rt].r <= r){
        return tr[rt].key;
    }
    push_down(rt);
    int sl = Query(rt<<1, l, r);
    int sr = Query(rt<<1|1, l, r);
    return sl>sr?sl:sr;
}

int fun(int x,int y,int z) //确定更新区间
{
    while(pre[x] != pre[y]){ //更新到最近公共祖先
        if(deep[pre[x]] < deep[pre[y]])//先更新深度深的
            swap(x,y);
        Updata(1,has[pre[x]],has[x],z);
        x = fa[pre[x]];
    }
    if(deep[x] > deep[y])
        swap(x,y);
    Updata(1, has[x], has[y], z);
    return 0;
}

int main()
{
    char str[5];
    while(~scanf("%d%d%d",&n,&m,&p))
    {
        for(int i = 1; i <= n; i++){
            scanf("%d",&mapn[i]);
        }
        top = 1;
        int x, y, z;
        memset(son, -1, sizeof(son));
        memset(head, -1, sizeof(head));
        for(int i = 0; i < m; i++){
            scanf("%d%d",&x,&y);
            add(x,y);
            add(y,x);
        }
        top = 1;
        fa[1] = deep[1] = 1;
        Dfs_1(1, 1);
        Dfs_2(1, 1);
        Build(1, 1, n);
        for(int i = 0; i < p; i++){
            scanf("%s",str);
            if(str[0] == 'Q'){
                scanf("%d",&x);
                printf("%d\n",Query(1,has[x],has[x]));
            }
            else{
                scanf("%d%d%d",&x,&y,&z);
                if(str[0] == 'D')
                    z = -z;
                fun(x,y,z);
            }
        }
    }
    return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: