【bzoj4034】[HAOI2015]树上操作

本文介绍了一种高效的数据结构处理方法——裸链剖分结合深度优先搜索序(DFS序),通过实例代码详细解释了如何利用这种方法解决树形结构上的区间更新和查询问题。文章涵盖关键数据结构定义、初始化过程、区间更新与查询操作实现。

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

裸的链剖+dfs序
需要注意的是tag也要用ll,不要怕费空间或者超时,出题人一般(注意是一般)不会卡常,因为这个调了半个小时

#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
typedef long long ll;
const int N=200010;
ll qx;
int n,m,te,sz;
int size[N],head[N],tp[N],fa[N],son[N],tree[N],num[N],leaf[N];
struct edge{
    int u,v,next;
}e[400010];
struct seg{
    int l,r;
    ll val,tag;
}tr[1000010];

inline int F()
{
    register int aa,bb;register char ch;
    while(ch=getchar(),(ch<'0'||ch>'9')&&ch!='-');ch=='-'?aa=bb=0:(aa=ch-'0',bb=1);
    while(ch=getchar(),ch<='9'&&ch>='0')aa=(aa<<3)+(aa<<1)+ch-'0';return bb?aa:-aa;
}
void clear()
{
    memset(head,0,sizeof(head));
    memset(son,0,sizeof(son));  
    size[0]=0;fa[1]=1,sz=0;
}
void add(int u,int v)
{
    e[++te].u=u;
    e[te].v=v;
    e[te].next=head[u];
    head[u]=te;
}
void dfs1(int x)
{
    size[x]=1;
    for (int i=head[x];i;i=e[i].next)
    {
        int v=e[i].v;
        if (v==fa[x])continue;
        fa[v]=x;
        dfs1(v);
        size[x]+=size[v];
        if (size[v]>size[son[x]])son[x]=v;
    }
}
void dfs2(int x,int chain)
{
    num[x]=++sz;
//  cout<<x<<' '<<sz<<endl;
    tp[x]=chain;
    if (!son[x])return;
    dfs2(son[x],chain);
    for (int i=head[x];i;i=e[i].next)
    {
        int v=e[i].v;
        if (v==fa[x]||v==son[x])continue;
        dfs2(v,v);
    }
}
void pushdown(int x)
{
    if (!tr[x].tag||tr[x].l==tr[x].r)return;
    int mid=(tr[x].l+tr[x].r)>>1;
    tr[x<<1].val+=(ll)(mid-tr[x].l+1)*tr[x].tag;
    tr[x<<1].tag+=tr[x].tag;
    tr[x<<1|1].val+=(ll)(tr[x].r-mid)*tr[x].tag;
    tr[x<<1|1].tag+=tr[x].tag;
    tr[x].tag=0;
}
void updata(int k){tr[k].val=tr[k<<1].val+tr[k<<1|1].val;}
void build(int x,int l,int r)
{
    tr[x].l=l,tr[x].r=r,tr[x].tag=0;
    if (l==r){tr[x].val=1ll*leaf[tree[l]];return;}
    int mid=(l+r)>>1;
    build(x<<1,l,mid);
    build(x<<1|1,mid+1,r);
    updata(x);
}
void change(int k,int x,int y,int z)
{
    pushdown(k);
    int l=tr[k].l,r=tr[k].r;
//  cout<<k<<' '<<x<<' '<<y<<' '<<l<<' '<<r<<endl;
    if (x<=l&&r<=y)
    {
        tr[k].val+=(ll)(r-l+1)*z;
        tr[k].tag=z;
        return;
    }
    int mid=(l+r)>>1;
    if (x<=mid)change(k<<1,x,y,z);
    if (y>mid)change(k<<1|1,x,y,z);
    updata(k);
}
void query(int k,int x,int y)
{
    pushdown(k);
    int l=tr[k].l,r=tr[k].r;
    if (x<=l&&r<=y)
    {
//      cout<<l<<' '<<r<<' '<<x<<' '<<y<<' '<<tr[k].val<<endl;
        qx+=tr[k].val;
        return;
    }
    int mid=(l+r)>>1;
    if (x<=mid)query(k<<1,x,y);
    if (y>mid)query(k<<1|1,x,y);
    updata(k);
}
ll solvequery(int x)
{
    qx=0;
    while(tp[x]!=1)
    {
        query(1,num[tp[x]],num[x]);
//      cout<<x<<' '<<tp[x]<<' '<<fa[tp[x]]<<' '<<qx<<endl;
        x=fa[tp[x]];
    }
    query(1,1,num[x]);
//  cout<<num[x]<<' '<<qx<<endl;
    return qx;
}
int main()
{
    clear();
    int a,x,y,u,v,op;
    n=F(),m=F();
    for (int i=1;i<=n;i++)leaf[i]=F();
    for (int i=1;i<n;++i)
    u=F(),v=F(),add(u,v),add(v,u);
    dfs1(1);
    dfs2(1,1);
    for (int i=1;i<=n;++i)
    tree[num[i]]=i;
//  cout<<endl<<endl;
//  for (int i=1;i<=n;++i)
//  cout<<num[i]<<' '<<tree[i]<<' '<<leaf[i]<<endl;
    build(1,1,n);
//  getchar();
    for (int i=1;i<=m;++i)
    {
        op=F();
        if (op==1)
        x=F(),a=F(),change(1,num[x],num[x],a);
        else if (op==2)
        x=F(),a=F(),change(1,num[x],num[x]+size[x]-1,a);
        else if (op==3)
        x=F(),printf("%lld\n",solvequery(x));
//      for (int i=1;i<=20;++i)
//      cout<<tr[i].l<<' '<<tr[i].r<<' '<<tr[i].val<<' '<<tr[i].tag<<endl;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值