HYSBZ 1036(树的统计) 树链剖分

传送门:树的统计

题意:

维护树上区间最值和区间和,加上单点修改

题解:

树链剖分的题,我们只要把线段树部分的操作写好,这题也就那回事,毕竟树链剖分是个模板,而且好理解,注意不要用cin和cout 会 TLE

在这里插入图片描述
AC代码:

#include<bits/stdc++.h>
using namespace std;
#define ll long long
const ll maxn=3e5+5;
ll cnt,cnx,head[maxn];
ll top[maxn],son[maxn],deep[maxn],a[maxn];
ll sizx[maxn],dfn[maxn],pre[maxn],w[maxn];
struct node
{
    ll to,nex;
} edge[maxn<<1];
void add(ll u,ll v)
{
    edge[cnx].to=v;
    edge[cnx].nex=head[u];
    head[u]=cnx++;
}
void dfs1(ll u,ll fa)
{
    deep[u]=deep[fa]+1;
    pre[u]=fa;
    sizx[u]=1;
    ll maxson=-1;
    for(ll i=head[u]; ~i; i=edge[i].nex)
    {
        ll v=edge[i].to;
        if(v!=fa)
        {
            dfs1(v,u);
            sizx[u]+=sizx[v];
            if(sizx[v]>maxson)
            {
                maxson=sizx[v];
                son[u]=v;
            }
        }
    }
}
void dfs2(ll u,ll t)
{
    top[u]=t;
    dfn[u]=++cnt;
    w[cnt]=a[u];
    if(!son[u])
    {
        return ;
    }
    dfs2(son[u],t);
    for(ll i=head[u]; ~i; i=edge[i].nex)
    {
        ll v=edge[i].to;
        if(v==pre[u]||v==son[u])
            continue;
        dfs2(v,v);
    }
}
struct yzj
{
    ll l,r,sum,ma;
} tr[maxn<<2];
void pushup(ll k)
{
    tr[k].sum=tr[k<<1].sum+tr[k<<1|1].sum;
    tr[k].ma=max(tr[k<<1].ma,tr[k<<1|1].ma);
}
void build(ll k,ll l,ll r)
{
    tr[k].l=l,tr[k].r=r;
    if(l==r)
    {
        tr[k].sum=w[l];
        tr[k].ma=w[l];
        return ;
    }
    ll mid=l+r>>1;
    build(k<<1,l,mid);
    build(k<<1|1,mid+1,r);
    pushup(k);
}
void modify(ll k,ll pos,ll w)
{
    if(tr[k].l==tr[k].r)
    {
        tr[k].ma=w;
        tr[k].sum=w;
        return ;
    }
    ll mid=tr[k].l+tr[k].r>>1;
    if(mid>=pos)
    {
        modify(k<<1,pos,w);
    }
    else
    {
        modify(k<<1|1,pos,w);
    }
    pushup(k);
}
ll askm(ll k,ll l,ll r)
{
    if(tr[k].l>=l&&tr[k].r<=r)
    {
        return tr[k].ma;
    }
    ll mid=tr[k].l+tr[k].r>>1;
    if(mid>=r)
    {
        return askm(k<<1,l,r);
    }
    else if(mid<l)
    {
        return askm(k<<1|1,l,r);
    }
    else
    {
        return max(askm(k<<1,l,mid),askm(k<<1|1,mid+1,r));
    }
}
ll asks(ll k,ll l,ll r)
{
    if(tr[k].l>=l&&tr[k].r<=r)
    {
        return tr[k].sum;
    }
    ll mid=tr[k].l+tr[k].r>>1;
    if(mid>=r)
    {
        return asks(k<<1,l,r);
    }
    else if(mid<l)
    {
        return asks(k<<1|1,l,r);
    }
    else
    {
        return (asks(k<<1,l,mid)+asks(k<<1|1,mid+1,r));
    }
}
ll optm(ll x,ll y)
{
    ll res=~0x3f3f3f3f;
    while(top[x]!=top[y])
    {
        if(deep[top[x]]<deep[top[y]])
            swap(x,y);
        res=max(res,askm(1,dfn[top[x]],dfn[x]));
        x=pre[top[x]];
    }
    if(deep[x]>deep[y])
    {
        swap(x,y);
    }
    res=max(res,askm(1,dfn[x],dfn[y]));
    return res;
}
ll opts(ll x,ll y)
{
    ll res=0;
    while(top[x]!=top[y])
    {
        if(deep[top[x]]<deep[top[y]])
            swap(x,y);
        res+=asks(1,dfn[top[x]],dfn[x]);
        x=pre[top[x]];
    }
    if(deep[x]>deep[y])
    {
        swap(x,y);
    }
    res+=asks(1,dfn[x],dfn[y]);
    return res;
}
int main()
{
    ll n,u,v;
    memset(head,-1,sizeof(head));
    scanf("%lld",&n);
    for(ll i=1; i<n; i++)
    {
        scanf("%lld %lld",&u,&v);
        add(u,v);
        add(v,u);
    }
    for(ll i=1; i<=n; i++)
        scanf("%lld",&a[i]);
    dfs1(1,0);
    dfs2(1,1);
    build(1,1,n);
    ll q;
    scanf("%lld",&q);
    char s[10];
    while(q--)
    {
        ll x,y;
        scanf("%s %lld %lld",s,&x,&y);
        if(strcmp(s,"QMAX")==0)
        {
            printf("%lld\n",optm(x,y));
        }
        else if(strcmp(s,"QSUM")==0)
        {
            printf("%lld\n",opts(x,y));
        }
        else
        {
            modify(1,dfn[x],y);
        }
    }
}
发布了222 篇原创文章 · 获赞 16 · 访问量 9733

猜你喜欢

转载自blog.csdn.net/yangzijiangac/article/details/104282918
今日推荐