• 图论:树链剖分模板


    点击查看折叠代码块
    /*
    树链剖分——重链剖分
    可以求LCA
    用线段树可以在树上维护区间最值、求区间和、求子树和等
    */
    #include <bits/stdc++.h>
    using namespace std;
    const int maxn=1e5+10;
    
    struct node{
        int v,next;
    }e[maxn<<1];
    int head[maxn],cnt=0,ct=0;
    int size[maxn];//子树的节点大小
    int son[maxn];//重儿子
    int top[maxn];//链头
    int fa[maxn];//父亲节点
    int d[maxn];//深度
    int id[maxn];//节点的新标号
    
    int sum[maxn<<2],lazy[maxn<<2],a[maxn],w[maxn];
    int mode,n,m,s;
    
    void add(int u,int v){
        e[++cnt].v=v;
        e[cnt].next=head[u];
        head[u]=cnt;
    }
    
    void dfs1(int x,int f,int deep){
        size[x]=1;
        d[x]=deep;
        fa[x]=f;
        int maxson=-1;
        for (int i=head[x];i;i=e[i].next){
            int v=e[i].v;
            if(v!=f){
                fa[v]=x;
                dfs1(v,x,deep+1);
    			size[x]+=size[v];
                if(size[v]>maxson){
                    son[x]=v;
                    maxson=size[v];
                }
            }
        }
    }
    
    void dfs2(int x,int tp){
        id[x]=++ct;
        w[ct]=a[x];//将原节点的信息复制 
        top[x]=tp;
        if(son[x]) dfs2(son[x],tp);//存在重儿子
        for (int i=head[x];i;i=e[i].next){
            int v=e[i].v;
            if(v!=fa[x] && v!=son[x]){//不是重儿子的其他节点,把自己做为链头
                dfs2(v,v);
            }
        }
    }
    
    int lca(int x,int y){//求LCA
        while(top[x]!=top[y]){
            if(d[top[x]]<d[top[y]]) swap(x,y);//保证x是所在链的链头深度较大的那个
            x=fa[top[x]];
        }
        return d[x]<d[y]?x:y;
    }
    
    //以下是线段树
    void pushdown(int l,int r,int rt){
        if(lazy[rt]){
            int m=(l+r)>>1;
            int d=lazy[rt];
            lazy[rt<<1]+=d;
            lazy[rt<<1|1]+=d;
            sum[rt<<1]=(sum[rt<<1]+(m-l+1)*d) % mode;
            sum[rt<<1|1]=(sum[rt<<1|1]+(r-m)*d) % mode;
            lazy[rt]=0;
        }
    }
    
    void pushup(int rt){
        sum[rt]=(sum[rt<<1]+sum[rt<<1|1]) % mode;
    }
    
    void build(int l,int r,int rt){
        if(l==r){
            sum[rt]=w[l];
            if(sum[rt]>mode) sum[rt] %=mode;
            return ;
        }
        int m=(l+r)>>1;
        build(l,m,rt<<1);
        build(m+1,r,rt<<1|1);
        pushup(rt);
    }
    
    void update(int L,int R,int v,int l,int r,int rt){
        if(L<=l && r<=R){
            lazy[rt]=(lazy[rt]+v) % mode;
            sum[rt]=(sum[rt]+(r-l+1)*v) % mode;
            return ;
        }
        pushdown(l,r,rt);
        int m=(l+r)>>1;
        if(L<=m) update(L,R,v,l,m,rt<<1);
        if(R>m) update(L,R,v,m+1,r,rt<<1|1);
        pushup(rt);
    }
    
    int query(int L,int R,int l,int r,int rt){
        if(L<=l && r<=R){
            return sum[rt] % mode;
        }
        pushdown(l,r,rt);
        int m=(l+r)>>1;
        int ans=0;
        if(L<=m) ans=(ans+query(L,R,l,m,rt<<1)) % mode;
        if(R>m) ans=(ans+query(L,R,m+1,r,rt<<1|1)) % mode;
        return ans;
    }
    /*线段树单点查询这里用不到
    int querypos(int pos,int l,int r,int rt){
    	if(l==r){
    		return sum[rt];
    	}
    	pushdown(l,r,rt);
    	int m=(l+r)>>1;
    	if(pos<=m) querypos(pos,l,m,rt<<1);
    	else querypos(pos,m+1,r,rt<<1|1);
    }
    */
    
    int Qdis(int x,int y){//操作2
        int ans=0;
        while(top[x]!=top[y]){//当两个点不在同一条链上
            if(d[top[x]]<d[top[y]]) swap(x,y);//把x点改为所在链顶端的深度更深的那个点
            ans+=query(id[top[x]],id[x],1,n,1);
            ans%=mode;
            x=fa[top[x]];//把x跳到x所在链顶端的那个点的上面一个点
        }
        //直到两个点处于一条链上
        if(d[x]>d[y]) swap(x,y);//把x点改为深度较小的那个点
        ans+=query(id[x],id[y],1,n,1);//这时再加上此时两个点的区间和即可
        return ans%=mode;
    }
    
    void Updis(int x,int y,int k){//操作1
        k%=mode;
        while(top[x]!=top[y]){
            if(d[top[x]]<d[top[y]]) swap(x,y);
            update(id[top[x]],id[x],k,1,n,1);
            x=fa[top[x]];
        }
        if(d[x]>d[y]) swap(x,y);
        update(id[x],id[y],k,1,n,1);
    }
    
    int Qnode(int x){//操作4
        return query(id[x],id[x]+size[x]-1,1,n,1) % mode;//子树区间右端点为id[x]+size[x]-1 
    }
    
    void Upnode(int x,int k){//操作3
        update(id[x],id[x]+size[x]-1,k,1,n,1);
    }
    
    int main(){
        scanf("%d%d%d%d",&n,&m,&s,&mode);
        for (int i=1;i<=n;i++){
            scanf("%d",&a[i]);
        }
        
        for (int i=1;i<=n-1;i++){
            int u,v;
            scanf("%d%d",&u,&v);
            add(u,v);add(v,u);
        }
        dfs1(s,0,1);dfs2(s,s);build(1,n,1);//预处理
        //询问
        
        for (int i=1;i<=m;i++){
            int op;
            scanf("%d",&op);
            if(op==1){
                int x,y,z;
                scanf("%d%d%d",&x,&y,&z);
                Updis(x,y,z);
            }
            else if(op==2){
                int x,y;
                scanf("%d%d",&x,&y);
                int ans=Qdis(x,y);
                printf("%d
    ",ans);
            }
            else if(op==3){
                int x,z;
                scanf("%d%d",&x,&z);
                Upnode(x,z);
            }
            else if(op==4){
                int x;
                scanf("%d",&x);
                int ans=Qnode(x);
                printf("%d
    ",ans);
            }
        }
        return 0;
    }
    
    
    
    你将不再是道具,而是成为人如其名的人
  • 相关阅读:
    对unsigned int和int进行移位操作的区别
    ctags支持的语言
    ubuntu使用问题与解决记录[持续更新]
    [转]python起步之卡尔曼滤波
    Android Studio的安装使用记录[持续更新]
    web.py实现jsonp
    关于python的import
    git常用命令[持续更新]
    flot图表的使用
    迁移web.py项目至git@osc的项目演示平台
  • 原文地址:https://www.cnblogs.com/wsl-lld/p/13393598.html
Copyright © 2020-2023  润新知