[Luogu P3384] chain split tree template

The basic idea is to split the tree chain tree split into a plurality of strands, reuse segment tree maintenance-related data and other data structures, it can be veryviolenceElegantly solve many problems.

Several basic concepts of the split tree chain:
Heavy son: for all the sons of the current node, the maximum size of a sub-tree is the son son weight (same size of the subtrees take a free)
light son: son is not heavy son light
weight edges: edges connecting the parent node and heavy son
light side: a parent node and connected to the light side of the son
of the heavy chain: heavy edge connected adjacent chain formed
of note are the following:
a leaf node is not re-son light no son;
for each of a heavy chain, light must be son onset;
single leaf node is a light heavy chain;
binding properties of the above three can draw a sectional tree: the heavy chain must include all possible nodes.
Tree chain split
(Source Baidu picture, invasion deleted)
red dot marks is the son of light, thick line is the heavy chain. With pictures to understand the concept.

Split Tree chain need to how to do it?
1, with DFS to mark the depth of each node, the parent node and heavy son.
2, for each node labeled a new number in the order of traversal by DFS DFS. Key points: first deal with the reprocessing of light weight son son
explanation: the first son of the heavy processing allows each point on the number of continuous heavy chain. Can be observed on the digital map, the line is the sequence of DFS. The numbers in a row, we can use the tree line to maintain the data.
These two steps are done even complete chain split tree, the next step is performed using other data structures maintained.

void add(ll sta,ll to)
{
    edge[++cnt].to=to;
    edge[cnt].next=head[sta];
    head[sta]=cnt;
}//链式前向星存树
void dfs1(ll now,ll fa,ll deep)
{   
    f[now]=fa;//记录父节点
    d[now]=deep;//记录深度(深度在区间求和时会用到)
    size[now]=1;//记录子树大小
    for (ll i=head[now];i!=0;i=edge[i].next)
    {
        if (edge[i].to==fa) continue;
        dfs1(edge[i].to,now,deep+1);
        size[now]+=size[edge[i].to];
        if (size[edge[i].to]>size[wson[now]]) wson[now]=edge[i].to;
        //取重儿子
    }
}
void dfs2(ll now,ll t)
{
    top[now]=t;//记录节点所在重链的起点
    id[now]=++cnt;//按照顺序编号
    rk[cnt]=now;//记录第cnt个点表示的是now节点,建树时会用到
    if (wson[now]) dfs2(wson[now],t);//优先处理重儿子
    for (ll i=head[now];i!=0;i=edge[i].next)
    {
        if (edge[i].to==wson[now]) continue;
        if (edge[i].to==f[now]) continue;
        dfs2(edge[i].to,edge[i].to);//一条重链的开头必然是轻儿子,链头即为它本身
    }
}

SPT two modification operations:

void treeupd(ll x,ll y,ll num)
{
    while (top[x]!=top[y])
    {
        if (d[top[x]]>d[top[y]])
        {
            segupd(1,1,n,id[top[x]],id[x],num);
            //segupd为线段树的更新函数
            x=f[top[x]];
        }
        else 
        {
            segupd(1,1,n,id[top[y]],id[y],num);
            //segupd为线段树的更新函数
            y=f[top[y]];
        }
    }
    //这一个循环的目的是,只要这两个节点不在一条重链上,
    //就让比较深的那一个往上跳到另一条链直到两者在同一条链上
    //又因为节点编号是连续的,所以可以很方便地给整条链加上修改操作
    if (id[x]<=id[y]) segupd(1,1,n,id[x],id[y],num);
    else segupd(1,1,n,id[y],id[x],num);
    //在最后两者位于同一条链上后,仍然要对他们两个之间的节点进行修改。
}

Summing operation will not be repeated, with the update operation is similar to the above.

The complete code

#include<cstdio>
#include<algorithm>
#define lson root<<1
#define rson root<<1|1
#define ll long long
#define mid ((l+r)>>1)
using namespace std;
struct data
{
    ll to,next;
}edge[200005];
ll cnt,head[200005],f[100005],d[100005],size[100005],wson[100005],top[100005],id[100005];
ll rk[100005],tree[800005],n,m,a[100005],p,tag[800005],r,x,y,z,flag;
void add(ll sta,ll to)
{
    edge[++cnt].to=to;
    edge[cnt].next=head[sta];
    head[sta]=cnt;
}
void dfs1(ll now,ll fa,ll deep)
{   
    f[now]=fa;
    d[now]=deep;
    size[now]=1;
    for (ll i=head[now];i!=0;i=edge[i].next)
    {
        if (edge[i].to==fa) continue;
        dfs1(edge[i].to,now,deep+1);
        size[now]+=size[edge[i].to];
        if (size[edge[i].to]>size[wson[now]]) wson[now]=edge[i].to;
    }
}
void dfs2(ll now,ll t)
{
    top[now]=t;
    id[now]=++cnt;
    rk[cnt]=now;
    if (wson[now]) dfs2(wson[now],t);
    for (ll i=head[now];i!=0;i=edge[i].next)
    {
        if (edge[i].to==wson[now]) continue;
        if (edge[i].to==f[now]) continue;
        dfs2(edge[i].to,edge[i].to);
    }
}
void build(ll root,ll l,ll r)
{
    if (l==r) 
    {
        tree[root]=a[rk[l]]%p;
        return ;
    }
    build(lson,l,mid);
    build(rson,mid+1,r);
    tree[root]=(tree[lson]+tree[rson])%p;   
}
void push_down(ll root,ll l,ll r)
{
    if (tag[root]==0) return ;
    tag[lson]+=tag[root];
    tag[rson]+=tag[root];
    tree[lson]+=tag[root]*(mid-l+1);
    tree[rson]+=tag[root]*(r-mid);
    tag[lson]%=p;
    tag[rson]%=p;
    tree[lson]%=p;
    tree[rson]%=p;
    tag[root]=0;
}
void segupd(ll root,ll l,ll r,ll al,ll ar,ll num)
{
    if (ar<l||r<al) return ;
    if (al<=l&&r<=ar)
    {
        tree[root]+=num*(r-l+1);
        tag[root]+=num;
        tree[root]%=p;
        tag[root]%=p;
        return ;
    }
    push_down(root,l,r);
    segupd(lson,l,mid,al,ar,num);
    segupd(rson,mid+1,r,al,ar,num);
    tree[root]=(tree[lson]+tree[rson])%p;
}
ll query(ll root,ll l,ll r,ll al,ll ar)
{
    if (ar<l||r<al) return 0;
    if (al<=l&&r<=ar) return tree[root]%p;
    push_down(root,l,r);
    return (query(lson,l,mid,al,ar)+query(rson,mid+1,r,al,ar))%p;
}
ll getsum(ll x,ll y)
{
    ll sum=0;
    while (top[x]!=top[y])
    {
        if (d[top[x]]>d[top[y]])
        {
            sum=(sum+query(1,1,n,id[top[x]],id[x]))%p;
            x=f[top[x]];
        }
        else 
        {
            sum=(sum+query(1,1,n,id[top[y]],id[y]))%p;
            y=f[top[y]];
        }
    }
    if (id[x]<=id[y]) sum=(sum+query(1,1,n,id[x],id[y]))%p;
    else sum=(sum+query(1,1,n,id[y],id[x]))%p;
    return sum;
}
void treeupd(ll x,ll y,ll num)
{
    while (top[x]!=top[y])
    {
        if (d[top[x]]>d[top[y]])
        {
            segupd(1,1,n,id[top[x]],id[x],num);
            x=f[top[x]];
        }
        else 
        {
            segupd(1,1,n,id[top[y]],id[y],num);
            y=f[top[y]];
        }
    }
    if (id[x]<=id[y]) segupd(1,1,n,id[x],id[y],num);
    else segupd(1,1,n,id[y],id[x],num);
}
int main()
{
    scanf("%lld%lld%lld%lld",&n,&m,&r,&p);
    for (ll i=1;i<=n;i++)
        scanf("%lld",&a[i]);
    for (ll i=1;i<n;i++)
    {
        scanf("%lld%lld",&x,&y);
        add(x,y);
        add(y,x);
    }
    cnt=0;
    dfs1(r,0,0);
    dfs2(r,r);
    build(1,1,n);
    for (ll i=1;i<=m;i++)
    {
        scanf("%lld",&flag);
        if (flag==1)
        {
            scanf("%lld%lld%lld",&x,&y,&z);
            treeupd(x,y,z);
        }
        if (flag==2)
        {
            scanf("%lld%lld",&x,&y);
            printf("%lld\n",getsum(x,y));
        }
        if (flag==3)
        {
            scanf("%lld%lld",&x,&z);
            segupd(1,1,n,id[x],id[x]+size[x]-1,z);
            //这里可以结合图片理解一下为什么。 
        }
        if (flag==4)
        {
            scanf("%lld",&x);
            printf("%lld\n",query(1,1,n,id[x],id[x]+size[x]-1));
        }
    }
    return 0;
} 

Guess you like

Origin www.cnblogs.com/notscience/p/11798342.html