• luogu P3384 【模板】树链剖分



    luogu P3384 【模板】树链剖分##

      Time Limit: 1 Sec
      Memory Limit: 128 MB

    Description###

       如题,已知一棵包含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为根节点的子树内所有节点值之和
     

    Input###

      第一行包含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
     

    Output###

       输出包含若干行,分别依次表示每个操作2或操作4所得的结果(对P取模)
     

    Sample Input###

      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
     

    Sample Output###

      2
      21
        

    HINT

       说明
       时空限制:1s,128M
      
       数据规模:
      
       对于30%的数据:(N leq 10, M leq 10)
       对于70%的数据: (N leq {10}^3, M leq {10}^3)
       对于100%的数据: (N leq {10}^5, M leq {10}^5)
      ( 其实,纯随机生成的树LCA+暴力是能过的,可是,你觉得可能是纯随机的么233 )
      样例说明:
      树的结构如下:
      
      各个操作如下:
      
      故输出应依次为2、21(重要的事情说三遍:记得取模)

    题目地址:   luogu P3384 【模板】树链剖分

    题目大意: 已经很简洁了

    题解:

      树剖模板写半天
      ghydalao天下第一


    AC代码

    #include <stdio.h>
    #include <algorithm>
    #define ll long long
    using namespace std;
    const int N=1e5+5;
    int n,Q,rt,Mod;
    int a[N];
    inline int read(){
    	int x=0,f=1;char ch=getchar();
    	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    	while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    	return x*f;
    }
    struct edge{
        int to,next;
    }e[N+N];
    int cnt_edge,last[N];
    inline void add_edge(int u,int v){
        e[++cnt_edge]=(edge){v,last[u]};last[u]=cnt_edge;
    }
    int fa[N],sz[N],dep[N],son[N];
    void dfs1(int u,int father){
        fa[u]=father;sz[u]=1;
        dep[u]=dep[father]+1;
        for(int i=last[u];i;i=e[i].next){
            int v=e[i].to;
            if(v==father)continue;
            dfs1(v,u);
            sz[u]+=sz[v];
            if(sz[son[u]]<sz[v])
                son[u]=v;
        }
    }
    int Knum,top[N],pos[N],sop[N],End[N];
    void dfs2(int u,int chain){
        top[u]=chain;
        pos[u]=++Knum;
        sop[Knum]=u;
        if(!son[u]){
            End[u]=Knum;
            return;
        }
        dfs2(son[u],chain);
        for(int i=last[u];i;i=e[i].next){
            int v=e[i].to;
            if(v!=fa[u] && v!=son[u])
                dfs2(v,v);
        }
        End[u]=Knum;
    }
    inline int mo(int x){
        return (x>=Mod) ? x-Mod : x;
    }
    int sum[N<<2],tag[N<<2];
    inline void pushdown(int k,int l,int r,int mid){
        if(!tag[k])return;
        sum[k<<1]=mo(sum[k<<1]+(ll)(mid-l+1)*tag[k]%Mod);
        sum[k<<1|1]=mo(sum[k<<1|1]+(ll)(r-mid)*tag[k]%Mod);
        tag[k<<1]=mo(tag[k<<1]+tag[k]);
        tag[k<<1|1]=mo(tag[k<<1|1]+tag[k]);
        tag[k]=0;
    }
    inline void pushup(int k){
        sum[k]=mo(sum[k<<1]+sum[k<<1|1]);
    }
    void build(int k,int l,int r){
        if(l==r){
            sum[k]=a[sop[l]];
            return;
        }
        int mid=(l+r)>>1;
        build(k<<1,l,mid);
        build(k<<1|1,mid+1,r);
        pushup(k);
    }
    void change(int k,int l,int r,int L,int R,int val){
        if(l==L && R==r){
            sum[k]=mo(sum[k]+(ll)(r-l+1)*val%Mod);
            tag[k]=mo(tag[k]+val);
            return;
        }
        int mid=(l+r)>>1;
        pushdown(k,l,r,mid);
        if(R<=mid)change(k<<1,l,mid,L,R,val);
        else if(L>mid)change(k<<1|1,mid+1,r,L,R,val);
        else change(k<<1,l,mid,L,mid,val),change(k<<1|1,mid+1,r,mid+1,R,val);
        pushup(k);
    }
    int query(int k,int l,int r,int L,int R){
        if(l==L && R==r)return sum[k];
        int mid=(l+r)>>1;
        pushdown(k,l,r,mid);
        if(R<=mid)return query(k<<1,l,mid,L,R);
        else if(L>mid)return query(k<<1|1,mid+1,r,L,R);
        else return mo(query(k<<1,l,mid,L,mid)+query(k<<1|1,mid+1,r,mid+1,R));
    }
    void update_path(int a,int b,int val){
        while(top[a]!=top[b]){
            if(dep[top[a]]<dep[top[b]])swap(a,b);
            change(1,1,n,pos[top[a]],pos[a],val);
            a=fa[top[a]];
        }
        if(dep[a]<dep[b])swap(a,b);
        change(1,1,n,pos[b],pos[a],val);
    }
    int query_path(int a,int b){
        int res=0;
        while(top[a]!=top[b]){
            if(dep[top[a]]<dep[top[b]])swap(a,b);
            res=mo(res+query(1,1,n,pos[top[a]],pos[a]));
            a=fa[top[a]];
        }
        if(dep[a]<dep[b])swap(a,b);
        res=mo(res+query(1,1,n,pos[b],pos[a]));
        return res;
    }
    inline void update_subtree(int x,int val){
        change(1,1,n,pos[x],End[x],val);
    }
    inline int query_subtree(int x){
        return query(1,1,n,pos[x],End[x]);
    }
    int main(){
        n=read(),Q=read(),rt=read(),Mod=read();
        for(int i=1;i<=n;i++)a[i]=read();
        for(int i=1;i<n;i++){
            int u=read(),v=read();
            add_edge(u,v);
            add_edge(v,u);
        }
        dfs1(rt,0);
        dfs2(rt,rt);
        build(1,1,n);
        while(Q--){
            int cas=read();
            if(cas==1){
                int x=read(),y=read(),val=read();
                update_path(x,y,val);
            }else if(cas==2){
                int x=read(),y=read();
                printf("%d
    ",query_path(x,y));
            }else if(cas==3){
                int x=read(),val=read();
                update_subtree(x,val);
            }else{
                int x=read();
                printf("%d
    ",query_subtree(x));
            }
        }
        return 0;
    }
    


      作者:skl_win
      出处:https://www.cnblogs.com/shaokele/
      本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

  • 相关阅读:
    SQLServer2008 行转列2
    SQLServer2008 行转列
    关于删除数据仓库的数据
    PowerDesign不让name和code联动
    提高SQL查询效率(SQL优化)(转载)
    SQL优化----百万数据查询优化(转载)
    运行程序向一个Java类中动态添加注解。
    开阔自己的视野,勇敢的接触新知识(转)
    [置顶] JAVA识别身份证号码,H5识别身份证号码,tesseract-ocr识别(一)(转)
    一个谷歌程序员的算法学习之路
  • 原文地址:https://www.cnblogs.com/shaokele/p/9927769.html
Copyright © 2020-2023  润新知