zoukankan      html  css  js  c++  java
  • P3384 【模板】树链剖分

    chuansongmen

    题目描述

    如题,已知一棵包含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 leq 10, M leq 10N10,M10

    对于70%的数据: N leq {10}^3, M leq {10}^3N103​​,M103​​

    对于100%的数据: N leq {10}^5, M leq {10}^5N105​​,M105​​

    ( 其实,纯随机生成的树LCA+暴力是能过的,可是,你觉得可能是纯随机的么233 )

    样例说明:

    树的结构如下:

    各个操作如下:

    故输出应依次为2、21(重要的事情说三遍:记得取模)

     code

    #include<cstdio>
    #include<iostream>
    using namespace std;
    const int maxn=500005;
    typedef long long LL;
    int n,m,u,v,t,r,sumedge,temp;
    LL mod;
    int head[maxn],son[maxn],dad[maxn],top[maxn],heavy_son[maxn];
    int id[maxn],real[maxn],depth[maxn],a[maxn];
    struct Edge{
        int x,y,nxt;
        Edge(int x=0,int y=0,int nxt=0):
            x(x),y(y),nxt(nxt){}
    }edge[maxn];
    struct segment_tree{
        LL l,r,sum,tag;
    }tr[maxn];
    void add(int x,int y){
        edge[++sumedge]=Edge(x,y,head[x]);
        head[x]=sumedge;
    }
    void dfs1(int k,int fa){
        dad[k]=fa;depth[k]=depth[fa]+1;
        son[k]=1;
        for(int i=head[k];i;i=edge[i].nxt){
            int v=edge[i].y;
            if(v!=fa){
                dfs1(v,k);
                son[k]+=son[v];
                if(!heavy_son[k]||son[heavy_son[k]]<son[v])
                heavy_son[k]=v;
            }
        }
    }
    void dfs2(int k,int fir){
        top[k]=fir;id[k]=++temp;
        real[temp]=k;
        if(!heavy_son[k])return;
        dfs2(heavy_son[k],fir);
        for(int i=head[k];i;i=edge[i].nxt){
            int v=edge[i].y;
            if(v!=dad[k]&&v!=heavy_son[k])
            dfs2(v,v);
        }
    }
    void pushup(int rt){
        tr[rt].sum=tr[rt<<1].sum+tr[rt<<1|1].sum;
    }
    void pushdown(int rt){
        tr[rt<<1].tag+=tr[rt].tag;
        tr[rt<<1].sum+=tr[rt].tag*(tr[rt<<1].r-tr[rt<<1].l+1);
        tr[rt<<1|1].tag+=tr[rt].tag;
        tr[rt<<1|1].sum+=tr[rt].tag*(tr[rt<<1|1].r-tr[rt<<1|1].l+1);
        tr[rt].tag=0;
        return;
    }
    
    void build(int rt,int l,int r){
        tr[rt].l=l;tr[rt].r=r;
        if(l==r){
            tr[rt].sum=a[real[l]];
            return;
        }
        int mid=(l+r)>>1;
        build(rt<<1,l,mid);build(rt<<1|1,mid+1,r);
        pushup(rt);
    }
    
    void update(int now,int ll,int rr,int x){
        if(ll<=tr[now].l&&tr[now].r<=rr){
            tr[now].sum+=(tr[now].r-tr[now].l+1)*x;
            tr[now].tag+=x;
            return;
        }
        pushdown(now);
        int mid=(tr[now].l+tr[now].r)>>1;
        if(rr<=mid)update(now<<1,ll,rr,x);
        else if(ll>mid)update(now<<1|1,ll,rr,x);
        else {
            update(now<<1,ll,mid,x);
            update(now<<1|1,mid+1,rr,x);
        }
        pushup(now);//***
    }
    LL query_sum(int now,int ll,int rr){
        if(ll<=tr[now].l&&tr[now].r<=rr){
            return tr[now].sum;
        }
        pushdown(now);
        int mid=(tr[now].l+tr[now].r)>>1;
        if(rr<=mid)return query_sum(now<<1,ll,rr);
        else if(ll>mid)return query_sum(now<<1|1,ll,rr);
        else{
            return query_sum(now<<1,ll,mid)+query_sum(now<<1|1,mid+1,rr);
        }
    }
    void change(int u,int v,LL x){
        int tu=top[u],tv=top[v];
        while(tu!=tv){
            if(depth[tu]<depth[tv]){
                swap(tu,tv);swap(u,v);
            }
            update(1,id[tu],id[u],x);
            u=dad[tu];
            tu=top[u];
        }
        if(depth[u]>depth[v])swap(u,v);
        update(1,id[u],id[v],x);
    }
    int find_sum(int u,int v){
        LL sum=0;
        int tu=top[u],tv=top[v];
        while(tu!=tv){
            if(depth[tu]<depth[tv]){
                swap(tu,tv);
                swap(u,v);
            }
            sum+=query_sum(1,id[tu],id[u]);
            sum%=mod;
            u=dad[tu];
            tu=top[u];
        }
        if(depth[u]>depth[v])swap(u,v);
        sum+=query_sum(1,id[u],id[v]);
        return sum%mod;
    }
    
    void root_add(int now,LL x){
        int begin=id[now];
        int ed=id[now]+son[now]-1;
        update(1,begin,ed,x);
    }
    LL root_sum(int now){
        int begin=id[now];
        int ed=id[now]+son[now]-1;
        return query_sum(1,begin,ed)%mod;
    }
    
    int main(){
        scanf("%d%d%d%lld",&n,&m,&r,&mod);
        for(int i=1;i<=n;i++)scanf("%d",&a[i]);
        for(int i=1;i<n;i++){
            scanf("%d%d",&u,&v);
            add(u,v);add(v,u);
        }
        dfs1(r,0);dfs2(r,r);
        build(1,1,temp);
        for(int i=0;i<m;i++){
            int t,x,y,z;
            scanf("%d",&t);
            if(t==1){
                scanf("%d%d%d",&x,&y,&z);
                change(x,y,z);
            }else if(t==2){
                scanf("%d%d",&x,&y);
                printf("%lld
    ",find_sum(x,y));
            }else if(t==3){
                scanf("%d%d",&x,&y);
                root_add(x,y);
            }else if(t==4){
                scanf("%d",&x);
                printf("%lld
    ",root_sum(x));
            }
        }
        return 0;
    } 
  • 相关阅读:
    动态规划-神奇的口袋V1
    独立项目-建立Web服务器-00
    连接数据库时出现:SQL Server 建立连接时出现与网络相关的或特定于实例的错误
    独立项目-MemoryStream-内存数据读写-01
    独立项目-场景刷怪、小怪AI、主角战斗、小怪死亡-01
    独立项目-角色控制器FSM-FSM有限状态机-03
    独立项目-角色控制器FSM-AnimatorController学习-02
    独立项目-角色控制器FSM-学习内容-01
    Unity中的UGUI之Rect Transform__02
    矩阵的平移、旋转与缩放
  • 原文地址:https://www.cnblogs.com/zzyh/p/7421203.html
Copyright © 2011-2022 走看看