树链板子

题目链接

可以解决的问题:
(1)从 x 到 y 最短路径上的结点值 + z
(2)求从 x 到 y 最短路径的结点值之和
(3)以 x 为根节点的子树内,结点值 + z
(4)求以 x 为根节点的子树内,所有节点值之和

理一下思路吧。。贴板子贴多了今天自己写了写dfs有些信息写不全。。
第一个dfs解决的东西:因为是按照正常dfs顺序遍历的,所以可以记录一些树上的信息: 深度 大小 ( 计算重儿子 ) 找重儿子(为下面剖分指明方向) 记录父亲节点
第二个dfs解决的东西:划分轻重链,按照轻重链将树变成区间,既然变成区间了,那么还需要顺便把原来在树上的信息转换成区间信息。

#include<cstdio>
#include<iostream>
#include<string>
#include<cstring>
#include<map>
#include<cmath>
#include<cctype>
#include<vector>
#include<set>
#include<queue>
#include<algorithm>
#include<sstream>
#define X first
#define Y second
#define L (u<<1)
#define R (u<<1|1)
#define Mid (tr[u].l+tr[u].r>>1)
#define Len(u) (tr[u].r-tr[u].l+1)
using namespace std;

typedef long long LL;
typedef pair<int,int> PII;

const int N=100010,INF=0x3f3f3f3f;
const double eps=1e-6;

int n,m,root,mod;
int in[N],depth[N],top[N],fa[N],son[N],se[N],tot;
int e[N*2],ne[N*2],h[N],idx;
int wt[N],w[N];
LL ans;

struct Node
{
    int l,r;
    LL sum,lazy;
}tr[N<<2];

void add(int a,int b)
{
    e[idx]=b,ne[idx]=h[a],h[a]=idx++;
}

void dfs1(int u,int f,int d)
{
    se[u]=1,depth[u]=d;//大小和深度
    fa[u]=f;//父节点
    int mx=-1;
    for(int i=h[u];~i;i=ne[i])
    {
        int j=e[i];
        if(j==f) continue;
        dfs1(j,u,d+1);
        se[u]+=se[j];//更新大小
        if(mx<se[j]) son[u]=j,mx=se[j];//更新重儿子
    }
}

void dfs2(int u,int t)
{
    in[u]=++tot;//将树变成区间
    wt[tot]=w[u];//更新新的区间的点权值
    top[u]=t;//记录当前链的起点
    if(son[u]==0) return;//没有叶子结点返回
    dfs2(son[u],t);
    for(int i=h[u];~i;i=ne[i])
    {
        int j=e[i];
        if(j==fa[u]||j==son[u]) continue;
        dfs2(j,j);//轻链起点为自己
    }
}
//正常线段树维护
void pushup(int u)
{
    tr[u].sum=(tr[L].sum+tr[R].sum)%mod;
}

void pushdown(int u)
{
    if(tr[u].lazy==0) return;
    tr[L].sum+=tr[u].lazy*Len(L)%mod,tr[R].sum+=tr[u].lazy*Len(R)%mod;
    tr[L].sum%=mod,tr[R].sum%=mod;
    tr[L].lazy+=tr[u].lazy,tr[R].lazy+=tr[u].lazy;
    tr[L].lazy%=mod,tr[R].lazy%=mod;
    tr[u].lazy=0;
}

void build(int u,int l,int r)
{
    tr[u]={l,r};
    if(l==r)
    {
        tr[u].sum=wt[l]%mod;
        return;
    }
    build(L,l,Mid),build(R,Mid+1,r);
    pushup(u);
}

void modify(int u,int l,int r,int c)
{
    if(tr[u].l>=l&&tr[u].r<=r)
    {
        tr[u].sum=(tr[u].sum+c*Len(u)%mod)%mod;
        tr[u].lazy=(tr[u].lazy+c)%mod;
        return;
    }
    pushdown(u);
    if(l<=Mid) modify(L,l,r,c);
    if(r>Mid) modify(R,l,r,c);
    pushup(u);
}

int query(int u,int l,int r)
{
    if(tr[u].l>=l&&tr[u].r<=r)
        return tr[u].sum;
    pushdown(u);
    LL t=0;
    if(l<=Mid) t+=query(L,l,r);
    if(r>Mid) t=(t+query(R,l,r))%mod;
    return t%mod;
}
//询问
void uprange(int x,int y,int z)
{
    while(top[x]!=top[y])
    {
        if(depth[top[x]]<depth[top[y]]) swap(x,y);
        modify(1,in[top[x]],in[x],z);
        x=fa[top[x]];
    }
    if(depth[x]<depth[y]) swap(x,y);
    modify(1,in[y],in[x],z);
}

void qrange(int x,int y)
{
    LL res=0;
    while(top[x]!=top[y])
    {
        if(depth[top[x]]<depth[top[y]]) swap(x,y);
        res+=query(1,in[top[x]],in[x]);
        res%=mod;
        x=fa[top[x]];
    }
    if(depth[x]<depth[y]) swap(x,y);
    res+=query(1,in[y],in[x])%mod;
    cout<<res%mod<<endl;
}

void upson(int x,int y)
{
    modify(1,in[x],in[x]+se[x]-1,y);
    return;
}

void qson(int x)
{
    LL res=query(1,in[x],in[x]+se[x]-1)%mod;
    cout<<res<<endl;
}

int main()
{
//	ios::sync_with_stdio(false);
//	cin.tie(0);

    memset(h,-1,sizeof h);
    cin>>n>>m>>root>>mod;
    for(int i=1;i<=n;i++)
        scanf("%d",&w[i]);
    for(int i=1;i<=n-1;i++)
    {
        int u,v;
        scanf("%d%d",&u,&v);
        add(u,v),add(v,u);
    }
    dfs1(root,-1,1);
    dfs2(root,root);
    build(1,1,n);
    while(m--)
    {
        int op,l,r;
        scanf("%d",&op);
        if(op==1)
        {
            int x,y,z;
            scanf("%d%d%d",&x,&y,&z);
            uprange(x,y,z);
        }
        else if(op==2)
        {
            int x,y;
            scanf("%d%d",&x,&y);
            qrange(x,y);
        }
        else if(op==3)
        {
            int x,y;
            scanf("%d%d",&x,&y);
            upson(x,y);
        }
        else
        {
            int x;
            scanf("%d",&x);
            qson(x);
        }
    }






	return 0;
}
/*

*/








猜你喜欢

转载自blog.csdn.net/DaNIelLAk/article/details/106444836
今日推荐