重链剖分模板

重链剖分模板

(求解dfs序的代码块应该放在第二个dfs里,即求重儿子的同时求dfs序,这样才能保证同一条链上的结点dfs序连续)

/**********
明天你是否会想起
昨天未调完的题
明天你是否还惦记
考场写挂的暴力
**********/
#include<bits/stdc++.h>
#define int long long
#define endl '\n'
using namespace std;
const int mod=1e18;//按题目要求随时修改.
void read(int &x){
    int f=1;x=0;char s=getchar();
    while(s>'9'||s<'0'){if(s=='-')f=-1;s=getchar();}
    while(s<='9'&&s>='0'){x=x*10%mod+(s-'0')%mod;s=getchar();}//改成了取模~~
    x=x%mod*f;//改成了取模~
}
const int N=1e5+10;
struct xds
{
    int l,r,sum;
    int lazy;
}xd[4*N];
​
vector<int>f[N];
int n,m,root,p;
int fa[N],dep[N],sum[N],son[N],top[N];
int dfs_x[N],fid_x[N];///dfs_x-->给定树上的点在线段树里对应的序号,即dfs序
/// fid_x-->线段树里的序号对应给定树的序号.
int val[N];
int tot;
//俩遍dfs进行树剖
void dfs(int father,int cur)
{
    sum[cur]=1;
    for(auto v:f[cur])
    {
        if(v==father) continue;
        dep[v]=dep[cur]+1;
        fa[v]=cur;
        dfs(cur,v);
        sum[cur]+=sum[v];
        if(sum[v]>sum[son[cur]]) son[cur]=v;
    }
}
void dfs2(int fcur,int cur)
{
    top[cur]=fcur;
    tot++;
    dfs_x[cur]=tot;//dfs序
    fid_x[tot]=cur;//存一下dfs序对应的原先树的编号,方便后面线段树初始化值
    if(son[cur]) dfs2(fcur,son[cur]);
    for(auto v:f[cur])
    {
        if(v==fa[cur]||v==son[cur]) continue;
        dfs2(v,v);
    }
}
///线段树,带求和懒标记
void pushup(int u)
{
    xd[u].sum=xd[u<<1].sum+xd[u<<1|1].sum;
}
void build(int u,int l,int r)
{
    if(l==r)
    {
        // cout<<val[fid_x[l]]<<endl;
        xd[u] = {l, r, val[fid_x[l]], 0};
    }
    else
    {
        int mid=l+r>>1;
        xd[u]={l,r,0,0};
        build(u<<1,l,mid),build(u<<1|1,mid+1,r);
        pushup(u);
    }
}
void pushdown(int u)
{
    if(xd[u].lazy)
    {
        xd[u<<1].sum+=xd[u].lazy*(xd[u<<1].r-xd[u<<1].l+1);
        xd[u<<1|1].sum+=xd[u].lazy*(xd[u<<1|1].r-xd[u<<1|1].l+1);
        xd[u<<1].lazy+=xd[u].lazy;
        xd[u<<1|1].lazy+=xd[u].lazy;
        xd[u].lazy=0;
    }
}
void motify(int u,int l,int r,int c)
{
    if(xd[u].l>=l&&xd[u].r<=r)
    {
        xd[u].sum+=(xd[u].r-xd[u].l+1)*c;
        xd[u].lazy+=c;
    }
    else
    {
        pushdown(u);
        int mid=xd[u].l+xd[u].r>>1;
        if(l<=mid) motify(u<<1,l,r,c);
        if(r>mid) motify(u<<1|1,l,r,c);
        pushup(u);
    }
}
int query(int u,int l,int r)
{
    if(xd[u].l>=l&&xd[u].r<=r) return xd[u].sum;
    else
    {
        pushdown(u);
        int mid=xd[u].l+xd[u].r>>1;
        int res=0;
        if(l<=mid) res=query(u<<1,l,r);
        if(r>mid) res+=query(u<<1|1,l,r);
        return res;
    }
}//俩个操作,求和和修改路径上的值
void cli(int l,int r,int c)
{
    while(top[l]!=top[r])
    {
        if(dep[top[l]]>dep[top[r]])
        {
            motify(1,dfs_x[top[l]],dfs_x[l],c);
            l=fa[top[l]];
        }
        else
        {
            motify(1,dfs_x[top[r]],dfs_x[r],c);
            r=fa[top[r]];
        }
    }
    int l_2=min(dfs_x[l],dfs_x[r]);
    int r_2=max(dfs_x[l],dfs_x[r]);
    motify(1,l_2,r_2,c);
}
int cli2(int l,int r)
{
    int res=0;
    while(top[l]!=top[r])
    {
        if(dep[top[l]]>dep[top[r]])
        {
            res+=query(1,dfs_x[top[l]],dfs_x[l]);
            l=fa[top[l]];
        }
        else
        {
            res+=query(1,dfs_x[top[r]],dfs_x[r]);
            r=fa[top[r]];
        }
    }
    int l_2=min(dfs_x[l],dfs_x[r]);
    int r_2=max(dfs_x[l],dfs_x[r]);
    res+=query(1,l_2,r_2);
    return res;
}
signed main()
{
    ios::sync_with_stdio(false);
    cin.tie(nullptr),cout.tie(nullptr);
    cin>>n>>m>>root>>p;
    for(int i=1;i<=n;i++)
    {
        cin>>val[i];
    }
    for(int i=0;i<n-1;i++)
    {
        int u,v;
        cin>>u>>v;
        f[u].push_back(v);
        f[v].push_back(u);
    }
    dfs(0,root);
    dfs2(root,root);
    build(1,1,n);
    while(m--)
    {
        int op,l,r,c;
        cin>>op;
        if(op==1)
        {
            cin>>l>>r>>c;
            cli(l,r,c);
        }
        else if(op==2)
        {
            cin>>l>>r;
            int ans=cli2(l,r);
            cout<<ans%p<<endl;
        }
        else if(op==3)
        {
            cin>>l>>c;
            motify(1,dfs_x[l],dfs_x[l]+sum[l]-1,c);//以l为根的子树的编号连续,且l的dfs序编号最小
        }
        else
        {
            cin>>l;
            cout<<query(1,dfs_x[l],dfs_x[l]+sum[l]-1)%p<<endl;
        }
    }
    return 0;
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值