ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

树链剖分板题入门:P3384重链剖分

2020-01-29 14:36:46  阅读:221  来源: 互联网

标签:sizx 剖分 板题 ll head 树链 edge maxn void


题目连接:重链剖分

思路:

把树剖剖分出来,然后就线段树上修改,注意每次先修改当前节点所在链的头的深度大的,然后让它为链的头的父亲即可,直道两个点,成为一条链上即可

老子搞了你这么多天,滚吧毒瘤题,hhh

AC代码:

#include<bits/stdc++.h>
using namespace std;
//树链剖分
#define ll long long
ll n,m,rt,p,cnt,cnx;
const ll maxn=1e5+5;
ll a[maxn],head[maxn],w[maxn];
ll pre[maxn],top[maxn],sizx[maxn],son[maxn],in[maxn],deep[maxn];
struct node
{
    ll to,nex;
} edge[maxn];
void add(ll u,ll v)
{
    edge[cnx].to=v;
    edge[cnx].nex=head[u];
    head[u]=cnx++;
}
void dfs1(ll u,ll fa)
{
    pre[u]=fa;
    deep[u]=deep[fa]+1;
    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;
    in[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==son[u]||v==pre[u])
            continue;
        dfs2(v,v);
    }
}
struct yzj
{
    ll l,r,sum,lazy;
} tr[maxn*4];
void pushup(ll k)
{
    tr[k].sum=(tr[k<<1].sum%p+tr[k<<1|1].sum%p)%p;
}
void pushdown(ll k)
{
    if(tr[k].l==tr[k].r)
    {
        return;
    }
    if(tr[k].lazy)
    {
        tr[k<<1].lazy+=tr[k].lazy;
        tr[k<<1|1].lazy+=tr[k].lazy;
        tr[k<<1].sum+=(tr[k<<1].r-tr[k<<1].l+1)*tr[k].lazy;
        tr[k<<1].sum%=p;
        tr[k<<1|1].sum+=(tr[k<<1|1].r-tr[k<<1|1].l+1)*tr[k].lazy;
        tr[k<<1|1].sum%=p;
        tr[k].lazy=0;
    }
}
void build(ll k,ll l,ll r)
{
    tr[k].l=l,tr[k].r=r;
    tr[k].lazy=0;
    if(l==r)
    {
        tr[k].sum=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 l,ll r,ll w)
{
    if(tr[k].l>=l&&tr[k].r<=r)
    {
        tr[k].lazy+=w;
        tr[k].sum+=(r-l+1)*w;
        tr[k].sum%=p;
        return ;
    }
    pushdown(k);
    ll mid=tr[k].l+tr[k].r>>1;
    if(mid>=r)
    {
        modify(k<<1,l,r,w);
    }
    else if(mid<l)
    {
        modify(k<<1|1,l,r,w);
    }
    else
    {
        modify(k<<1,l,mid,w);
        modify(k<<1|1,mid+1,r,w);
    }
    pushup(k);
}
ll query(ll k,ll l,ll r)
{

    if(tr[k].l==l&&tr[k].r==r)
    {
        return tr[k].sum%p;
    }
    pushdown(k);
    ll mid=tr[k].l+tr[k].r>>1;
    if(mid>=r)
    {
        return query(k<<1,l,r)%p;
    }
    else if(mid<l)
    {
        return query(k<<1|1,l,r)%p;
    }
    else
    {
        return (query(k<<1,l,mid)%p+query(k<<1|1,mid+1,r)%p)%p;
    }
}
void opt1(ll x,ll y,ll z)
{
    while(top[x]!=top[y])
    {
        if(deep[top[x]]<deep[top[y]])
            swap(x,y);
        modify(1,in[top[x]],in[x],z);
        x=pre[top[x]];
    }
    if(deep[x]>deep[y])
        swap(x,y);
    modify(1,in[x],in[y],z);

}
ll opt2(ll x,ll y)
{
    ll res=0;
     while(top[x]!=top[y])
    {
        if(deep[top[x]]<deep[top[y]])
            swap(x,y);
        res+=query(1,in[top[x]],in[x]);
        res%=p;
        x=pre[top[x]];
    }
    if(deep[x]>deep[y])
        swap(x,y);
    res+=query(1,in[x],in[y]);
    res%=p;
    return res;
}
void opt3(ll x,ll z)
{
    modify(1,in[x],in[x]+sizx[x]-1,z);
}
ll opt4(ll x)
{
    return query(1,in[x],in[x]+sizx[x]-1)%p;
}
int main()
{
    memset(head,-1,sizeof(head));
    scanf("%lld %lld %lld %lld",&n,&m,&rt,&p);
    for(ll i=1; i<=n; i++)
        scanf("%lld",&a[i]);
    ll u,v;
    for(ll i=1; i<n; i++)
    {
        scanf("%lld %lld",&u,&v);
        add(u,v);
        add(v,u);
    }
    dfs1(rt,0);
    dfs2(rt,rt);
    build(1,1,cnt);
    while(m--)
    {
        ll op,x,y,z;
        scanf("%lld",&op);
        if(op==1)
        {
            scanf("%lld %lld %lld",&x,&y,&z);
            opt1(x,y,z);
        }
        if(op==2)
        {
            scanf("%lld %lld",&x,&y);
            printf("%lld\n",opt2(x,y));
        }
        if(op==3)
        {
             scanf("%lld %lld",&x,&z);
             opt3(x,z);
        }
        if(op==4)
        {
            scanf("%lld",&x);
           printf("%lld\n",opt4(x));
        }

    }

}
Vain_拾荒者 发布了209 篇原创文章 · 获赞 12 · 访问量 8745 私信 关注

标签:sizx,剖分,板题,ll,head,树链,edge,maxn,void
来源: https://blog.csdn.net/yangzijiangac/article/details/104106677

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有