HDU 3966 Aragorn's Story(树链剖分)

本文通过一道具体题目介绍树链剖分技术的应用。文章详细解释了如何利用树链剖分来处理树上的区间修改和查询操作,并分享了避免内存溢出的经验教训。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题意:

给你一棵树,n个节点,每个节点有一个val,p次操作,一种是每次对u到v加或者减一个数,另一种是查询某个点的值

思路:

树链剖分水题,简单地维护一下就好。但是,这题真正坑的地方是MLE,看到discuss里面,很多人反映G++会出问题但是C++能AC,有人说因为hdu是windows会容易爆栈,需要手动扩栈。我经过血的教训,得出结论,如果这些都没有问题,请看看自己写的数组到底有没有问题,比如lazy有没有开四倍,链式前向星有没有开两倍等等,我因为lazy忘了开四倍红了一页。。。真是让人智熄

错误及反思:

吐槽一下,这题vector比链式前向星块很多

代码:

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<vector>
using namespace std;
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
const int N =50100;
int segtree[N*4];
int lazy[N*4];
int top[N],son[N],first[N],fa[N],id[N],val[N],depth[N],si[N];
vector<int> v[N];
int arr[N];
int n,m,q,tot=0,tid=0;


void build(int l,int r,int rt)
{
    if(l==r)
    {
        segtree[rt]=arr[l];
        return ;
    }
    int m=(l+r)/2;
    build(lson);
    build(rson);
    segtree[rt]=segtree[rt<<1]+segtree[rt<<1|1];
}
void dfs1(int now,int bef,int dep)
{
    depth[now]=dep;
    fa[now]=bef;
    si[now]=1;
    for(int i=0;i<v[now].size();i++)
        if(v[now][i]!=bef)
        {
            dfs1(v[now][i],now,dep+1);
            si[now]+=si[v[now][i]];
            if(son[now]==-1) son[now]=v[now][i];
            else son[now]=si[v[now][i]]>si[son[now]]?v[now][i]:son[now];
        }
}
void dfs2(int now,int tp)
{
    top[now]=tp;
    id[now]=tid++;
    if(son[now]!=-1) dfs2(son[now],tp);
    for(int i=0;i<v[now].size();i++)
        if(v[now][i]!=fa[now]&&v[now][i]!=son[now])
            dfs2(v[now][i],v[now][i]);
}
void pushdown(int l,int r,int rt)
{
    if(lazy[rt])
    {
        int m=(l+r)/2;
        lazy[rt<<1]+=lazy[rt];
        lazy[rt<<1|1]+=lazy[rt];
        segtree[rt<<1]+=lazy[rt]*(m-l+1);
        segtree[rt<<1|1]+=lazy[rt]*(r-m);
        lazy[rt]=0;
    }
}
void change(int L,int R,int v,int l,int r,int rt)
{
    if(L<=l&&R>=r)
    {
        lazy[rt]+=v;
        segtree[rt]+=v*(r-l+1);
        return ;
    }
    pushdown(l,r,rt);
    int m=(l+r)/2;
    if(m>=L) change(L,R,v,lson);
    if(m<R) change(L,R,v,rson);
    segtree[rt]=segtree[rt<<1]+segtree[rt<<1|1];
}
int query(int pos,int l,int r,int rt)
{
    if(l==r&&l==pos)
        return segtree[rt];
    pushdown(l,r,rt);
    int m=(l+r)/2;
    if(m>=pos) return query(pos,lson);
    return query(pos,rson);
}
void modify(int L,int R,int v)
{
    int f1=top[L],f2=top[R];
    while(f1!=f2)
    {
        if(depth[f1]<depth[f2])
        {
            swap(f1,f2);
            swap(L,R);
        }
        change(id[f1],id[L],v,0,tid-1,1);
        L=fa[f1];
        f1=top[L];
    }
    if(L==R)
    {
        change(id[L],id[R],v,0,tid-1,1);
        return;
    }
    else{
        if(depth[L]<depth[R]) swap(L,R);
        change(id[R],id[L],v,0,tid-1,1);
    }
}
int main()
{
    while(~scanf("%d%d%d",&n,&m,&q))
    {
        tid=0;
        memset(lazy,0,sizeof(lazy));
        memset(son,-1,sizeof(son));
        memset(first,-1,sizeof(first));
        memset(segtree,0,sizeof(segtree));
        for(int i=1;i<=n;i++)
            scanf("%d",&val[i]);
        for(int i=0;i<n-1;i++)
        {
            int ta,tb;
            scanf("%d%d",&ta,&tb);
            v[ta].push_back(tb);
            v[tb].push_back(ta);
        }
        dfs1(1,0,1);
        dfs2(1,1);
        for(int i=1;i<=n;i++)
            arr[id[i]]=val[i];
        build(0,tid-1,1);
        while(q--)
        {
            char temp[10];
            int ta,tb,tc;
            scanf("%s",temp);
            if(temp[0]=='Q')
            {
                scanf("%d",&ta);
                printf("%d\n",query(id[ta],0,tid-1,1));
            }
            else
            {
                scanf("%d%d%d",&ta,&tb,&tc);
                if(temp[0]=='D')
                    tc=-tc;
                modify(ta,tb,tc);
            }
        }
        for(int i=1;i<=n;i++) v[i].clear();

    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值