• 树链剖分


      对于树上路径上点权,边权问题,查询次数很多,如果用差分的话,每次查询前都有对c数组求一遍树上前缀和,然后dfs求个dis才能知道两点之间信息,这样的话对于修改然后查询,修改然后查询。。。。这样的复杂度就很高了,于是就要用树链剖分。

    数链剖分每次查询和修改的时间复杂度都是(logn)^2,

    下面贴几篇写得比较纤细的博客

    https://www.cnblogs.com/chinhhh/p/7965433.html     

    https://www.luogu.org/problemnew/solution/P3384?page=2

    模板题P3384

    #include<bits/stdc++.h>
    using namespace std;
    #define ls rt<<1
    #define rs (rt<<1)+1
    #define sjs srand(time(NULL));
    #define fuck(x) cout<<#x<<"     "<<x<<endl;
    const int maxn=1e5+10;
    struct edge
    {
        int v,nxt;
        edge(int v=0,int nxt=0){
            this->v=v;
            this->nxt=nxt;
        }
    }e[maxn<<1];
    int n,m,r,mod,tim,nod[maxn],head[maxn],sz[maxn],son[maxn],fa[maxn],dep[maxn],top[maxn],id[maxn],rk[maxn],sum[maxn<<2],lazy[maxn<<2];//son[i]表示重儿子,top[i]表示 1.i节点连了重链那就是所在重链的顶端节点,2.如果没连的话那就是它本身,id[i]表示i节点的dfs序,rk[i]是映射
    void dfs1(int now,int f)
    {
        sz[now]=1;
        fa[now]=f;
        dep[now]=dep[f]+1;
        for(int i=head[now];i;i=e[i].nxt)
        {
            int v=e[i].v;
            if(v==f) continue;
            dfs1(v,now);
            sz[now]+=sz[v];
            if(sz[v]>sz[son[now]])
                son[now]=v;
        }
    }
    void dfs2(int now,int t){
        top[now]=t;
        id[now]=++tim;
        rk[tim]=now;
        if(!son[now])
            return ;
        dfs2(son[now],t);
        for(int i=head[now];i;i=e[i].nxt)
        {
            int v=e[i].v;
            if(v!=son[now]&&v!=fa[now])
                dfs2(v,v);
        }
    }
    void pushup(int rt)
    {
        sum[rt]=(sum[ls]+sum[rs])%mod;
    }
    void pushdown(int rt,int L,int R)
    {
        if(lazy[rt])
        {
            int mid=(L+R)>>1;
            lazy[ls]+=lazy[rt];
            lazy[ls]%=mod;
            lazy[rs]+=lazy[rt];
            lazy[rs]%=mod;
            sum[ls]+=(mid-L+1)%mod*lazy[rt];
            sum[ls]%=mod;
            sum[rs]+=(R-mid)%mod*lazy[rt];
            sum[rs]%=mod;
            lazy[rt]=0;
        }
    }
    void build(int rt,int L,int R){
        if(L==R)
        {
            sum[rt]=nod[rk[L]]%mod;
            return ;
        }
        int mid=(L+R)>>1;
        build(ls,L,mid);
        build(rs,mid+1,R);
        pushup(rt);
    }
    void update(int rt,int L,int R,int l,int r,int k)
    {
        if(l<=L&&r>=R)
        {
            lazy[rt]+=k;
            lazy[rt]%=mod;
            sum[rt]+=(R-L+1)%mod*k;
            sum[rt]%=mod;
            return ;
        }
        pushdown(rt,L,R);
        int mid=(L+R)>>1;
        if(r<=mid)
            update(ls,L,mid,l,r,k);
        else
            if(l>=mid+1)
                update(rs,mid+1,R,l,r,k);
            else
            {
                update(ls,L,mid,l,r,k);
                update(rs,mid+1,R,l,r,k);
            }
        pushup(rt);
    }
    int query(int rt,int L,int R,int l,int r)
    {
        if(l<=L&&r>=R)
            return sum[rt];
        pushdown(rt,L,R);
        int mid=(L+R)>>1;
        if(r<=mid)
            return query(ls,L,mid,l,r);
        else
            if(l>=mid+1)
                return query(rs,mid+1,R,l,r);
            else
            {
                int ans=0;
                ans+=query(ls,L,mid,l,r);
                ans%=mod;
                ans+=query(rs,mid+1,R,l,r);
                ans%=mod;
                return ans;
            }
    }
    void updrange(int x,int y,int k)
    {
        int fx=top[x],fy=top[y];
        k%=mod;
        while(fx!=fy){
            if(dep[fx]>=dep[fy]){
                update(1,1,n,id[fx],id[x],k);
                x=fa[fx],fx=top[x];
            }
            else
            {
                update(1,1,n,id[fy],id[y],k);
                y=fa[fy],fy=top[y];
            }
        }
        if(id[x]<=id[y])
            update(1,1,n,id[x],id[y],k);
        else
            update(1,1,n,id[y],id[x],k);
    }
    int querange(int x,int y){
        int ans=0,fx=top[x],fy=top[y];
        while(fx!=fy){
            if(dep[fx]>=dep[fy]){
                ans+=query(1,1,n,id[fx],id[x]);
                ans%=mod;
                x=fa[fx],fx=top[x];
            }
            else{
                ans+=query(1,1,n,id[fy],id[y]);
                ans%=mod;
                y=fa[fy],fy=top[y];
            }
        }
        if(id[x]<=id[y])
            ans+=query(1,1,n,id[x],id[y]);
        else
            ans+=query(1,1,n,id[y],id[x]);
        ans%=mod;
        return ans;
    }
    void updsontree(int x,int y)
    {
        update(1,1,n,id[x],id[x]+sz[x]-1,y);
    }
    int quesontree(int x)
    {
        return query(1,1,n,id[x],id[x]+sz[x]-1);
    }
    int main(){
        int cnt=0;
        scanf("%d%d%d%d",&n,&m,&r,&mod);
        for(int i=1;i<=n;i++) scanf("%d",&nod[i]);
        for(int i=1;i<n;i++){
            int u,v;
            scanf("%d%d",&u,&v);
            e[++cnt]=edge(v,head[u]);
            head[u]=cnt;
            e[++cnt]=edge(u,head[v]);
            head[v]=cnt;
        }
        dfs1(r,0);
        dfs2(r,r);
        build(1,1,n);
        while(m--){
            int op,x,y,z;
            scanf("%d",&op);
            if(op==1)
            {
                scanf("%d%d%d",&x,&y,&z);
                updrange(x,y,z);
            }
            else
                if(op==2)
                {
                    scanf("%d%d",&x,&y);
                    printf("%d
    ",querange(x,y));
                }
                else
                    if(op==3){
                        scanf("%d%d",&x,&y);
                        updsontree(x,y);
                    }
                    else
                    {
                        scanf("%d",&x);
                        printf("%d
    ",quesontree(x));
                    }
        }
        return 0;
    }
    
  • 相关阅读:
    函数 out 传值 分割
    函数
    特殊集合
    集合
    数组

    穷举
    循环
    mac 软件安装
    实用信息查询接口
  • 原文地址:https://www.cnblogs.com/eason9906/p/11754750.html
Copyright © 2020-2023  润新知