洛谷3384——树链剖分模板

题目描述
如题,已知一棵包含N个结点的树(连通且无环),每个节点上包含一个数值,需要支持以下操作:
操作1: 格式: 1 x y z 表示将树从x到y结点最短路径上所有节点的值都加上z
操作2: 格式: 2 x y 表示求树从x到y结点最短路径上所有节点的值之和
操作3: 格式: 3 x z 表示将以x为根节点的子树内所有节点值都加上z
操作4: 格式: 4 x 表示求以x为根节点的子树内所有节点值之和
输入输出格式
输入格式:
第一行包含4个正整数N、M、R、P,分别表示树的结点个数、操作个数、根节点序号和取模数(即所有的输出结果均对此取模)。
接下来一行包含N个非负整数,分别依次表示各个节点上初始的数值。
接下来N-1行每行包含两个整数x、y,表示点x和点y之间连有一条边(保证无环且连通)
接下来M行每行包含若干个正整数,每行表示一个操作,格式如下:
操作1: 1 x y z
操作2: 2 x y
操作3: 3 x z
操作4: 4 x
输出格式:
输出包含若干行,分别依次表示每个操作2或操作4所得的结果(对P取模)
输入输出样例
输入样例#1:
5 5 2 24
7 3 7 8 0
1 2
1 5
3 1
4 1
3 4 2
3 2 2
4 5
1 5 1 3
2 1 3
输出样例#1:
2
21
说明
时空限制:1s,128M
数据规模:
对于30%的数据: N≤10,M≤10
对于70%的数据: N 10 3 N \leq {10}^3 , M 10 3 M \leq {10}^3
对于100%的数据: N 10 5 N \leq {10}^5 , M 10 5 M \leq {10}^5
( 其实,纯随机生成的树LCA+暴力是能过的,可是,你觉得可能是纯随机的么233 )

很简单的一个树剖板子了

支持四种操作:

1、链加
2、链求和
3、子树加
4、子树求和

其实可以dfs序可以做的

但这里为了练树剖我们还是用写树剖吧

链加

当两个点不在重链同一条重链上时,我们把顶端深度深的那条重链上的点跳到重链的父亲上,然后线段树维护区间加,直到两个点在同一条重链上后,再把两个点之间的区间加一下

链求和也是类似

当两个点不在同一条重链上时,把顶端深度深的点跳到重链的父亲,然后区间求和,最后两个点之间区间求和

子树加

直接在dfs序上维护区间加

子树求和

也直接在dfs序的区间上区间求和就是了

可以发现第1、2个操作因为要执行logn次,每次复杂度约为logn,所以复杂度为 l o g n 2 logn^2

而3、4个操作的复杂度是直接logn的


#include<bits/stdc++.h>
using namespace std;
#define mid ((l+r)/2)
inline int read(){
    char ch=getchar();
    int res=0;
    while(!isdigit(ch)) ch=getchar();
    while(isdigit(ch)) res=(res<<3)+(res<<1)+(ch^48),ch=getchar();
    return res;
}
int sum[400005],mark[400005],n,m,r,mod,adj[200005],nxt[200005],to[200004],cnt;
int fa[200005],son[200005],id[200005],dep[200005],siz[200005],top[200005],w[200005],val[200005];
inline void addedge(int u,int v){
    nxt[++cnt]=adj[u],adj[u]=cnt,to[cnt]=v;
    nxt[++cnt]=adj[v],adj[v]=cnt,to[cnt]=u;
}
int pushup(int rt)
{
    sum[rt] = (sum[rt << 1] + sum[rt << 1 | 1]) % mod;
}
inline void pushdown(int u,int len)
{
    if(mark[u])
    {
        mark[u*2]+=mark[u];
        mark[(u*2)+1]+=mark[u];
        sum[u*2]+=mark[u]*(len-(len>>1));
        sum[u*2]%=mod;
        sum[(u*2)+1]+=mark[u]*(len>>1);
        sum[(u*2)+1]%=mod;
        mark[u]=0;
    }
}
inline void buildtree(int u,int l,int r,int dep)
{
    if(l==r)
    {
            sum[u]=val[l];
            sum[u]%=mod;
            return ;
    }
    buildtree(u*2,l,mid,dep+1);
    buildtree((u*2)+1,mid+1,r,dep+1);
    pushup(u);
}
void update(int u,int l,int r,int L, int R, int c)
{
    if (L <= l && r <= R)
    {
        mark[u] += c;
        sum[u] += c * (r - l + 1);
        sum[u] %= mod;
        return;
    }
    pushdown(u, r - l + 1);
    int m = (l + r) >> 1;
    if (L <= m)
        update(u*2,l,m,L, R, c);
    if (R > m)
        update((u*2)+1,m+1,r,L, R, c);
    pushup(u);
}
inline int query(int u,int l,int r,int st,int des)
{
    if(l>des||r<st) return 0;
    int ans=0;
    if(st<=l&&r<=des)
    {
        return sum[u];
    }
    pushdown(u,r-l+1);
    if(st<=mid)
    {
        ans+=query(u*2,l,mid,st,des);
        ans%=mod;
    }
    if(mid<des)
    {
        ans+=query((u*2)+1,mid+1,r,st,des);
        ans%=mod;
    }
    return ans;
}
inline void dfs1(int u,int f)
{
    dep[u]=dep[f]+1;
    fa[u]=f,siz[u]=1;
    int maxs=-1;
    for(int e=adj[u];e;e=nxt[e])
    {
        int v=to[e];
        if(v==f) continue;
        dfs1(v,u);
        siz[u]+=siz[v];
        if(siz[v]>maxs)
        {
            son[u]=v;
            maxs=siz[v];
        }
    }
}
inline void dfs2(int u,int topfa)
{
    id[u]=++cnt;
    val[cnt]=w[u];
    top[u]=topfa;
    if(!son[u]) return;
    dfs2(son[u],topfa);
    for(int e=adj[u];e;e=nxt[e])
    {
        int v=to[e];
        if(v==son[u]||v==fa[u]) continue;
        dfs2(v,v);
    }
}
inline void uprange(int x,int y,int k)
{
    k%=mod;
    while(top[x]!=top[y])
    {
        if(dep[top[x]]<dep[top[y]]) swap(x,y);
        update(1,1,n,id[top[x]],id[x],k);
        x=fa[top[x]];
 	}
 	if(dep[x]>dep[y]) swap(x,y);
 	update(1,1,n,id[x],id[y],k);
}
inline int qrange(int x,int y)
{
    int ans=0;
    while(top[x]!=top[y])
    {
        if(dep[top[x]]<dep[top[y]]) swap(x,y);
        ans+=query(1,1,n,id[top[x]],id[x]);
        ans%=mod;
        x=fa[top[x]];
    }
    if(dep[x]>dep[y]) swap(x,y);
    ans+=query(1,1,n,id[x],id[y]);
    return ans%mod;
}
inline void upson(int x,int k){
    update(1,1,n,id[x],id[x]+siz[x]-1,k);
}
inline int qson(int x)
{
    return query(1,1,n,id[x],id[x]+siz[x]-1);
}
int main()
{
    int u, v;
    n=read(),m=read(),r=read(),mod=read();
    for (int i = 1; i <= n; i++)
    w[i]=read();
    for (int i = 1; i <= n - 1; i++)
    {
        u=read(),v=read();
        addedge(u, v);
    }
    cnt=0;
    dfs1(r, 0);
    dfs2(r, r);
    buildtree(1, 1,n,1); 
    while (m--)
    {
        int op, x, y, z;
        op=read();
        if (op == 1)
        {
            x=read(),y=read(),z=read();
            uprange(x, y, z);
        }
        else if (op == 2)
        {
            x=read(),y=read();
            printf("%d\n", qrange(x, y));
        }
        else if (op == 3)
        {
            x=read(),z=read();
            upson(x, z);
        }
        else if (op == 4)
        {
            x=read(); 
            printf("%d\n", qson(x));
        }
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_42555009/article/details/82955799