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

    传送门

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

    #include<bits/stdc++.h>
    using namespace std;
    inline int read(){
        int s=0,w=1;
        char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
        while(ch>='0'&&ch<='9'){s=s*10+ch-'0';ch=getchar();}
        return s*w;
    }
    int n,m,root,mod;
    int val[100005],sum[400005],add[400005];
    int size[100005],deep[100005],fa[100005],son[100005];
    int rev[400005],seg[100005],top[100005];
    int tot,head[100005],nxt[200005],to[200005];
    void add_edge(int a,int b){
        nxt[++tot]=head[a];head[a]=tot;to[tot]=b;
        nxt[++tot]=head[b];head[b]=tot;to[tot]=a;
    }
    void dfs1(int u,int father){
        size[u]=1;deep[u]=deep[father]+1;fa[u]=father;
        for(int i=head[u];i;i=nxt[i]){
    		int v=to[i];
    		if(v==father)continue;
    		dfs1(v,u);
    		size[u]+=size[v];
    		if(size[son[u]]<size[v])son[u]=v;
        }
    }
    void dfs2(int u,int father){
        if(son[u]){
    		top[son[u]]=top[u];
    		seg[son[u]]=++seg[0];
    		rev[seg[0]]=son[u];
    		dfs2(son[u],u);
        }
        for(int i=head[u];i;i=nxt[i]){
    		int v=to[i];
    		if(!top[v]){
    	    	top[v]=v;
    	    	seg[v]=++seg[0];
    	    	rev[seg[0]]=v; 
    	    	dfs2(v,u);
    		}
        }
    }
    void build(int k,int l,int r){
        if(l==r){sum[k]=val[rev[l]]%mod;return;}
        int mid=(l+r)>>1;
        build(k<<1,l,mid);build((k<<1)+1,mid+1,r);
        sum[k]=(sum[k<<1]+sum[(k<<1)+1])%mod;
    }
    void Add(int k,int l,int r,int val){
        add[k]=(add[k]+val)%mod;
        sum[k]=sum[k]%mod+((r-l+1)*val)%mod;
        return;
    }
    void pushdown(int k,int l,int r,int mid){
        if(add[k]==0)return;
        Add(k<<1,l,mid,add[k]);
        Add((k<<1)+1,mid+1,r,add[k]);
        add[k]=0;
    }
    void change(int k,int l,int r,int L,int R,int val){
        if(l>=L&&r<=R)return Add(k,l,r,val);
        int mid=(l+r)>>1;
        pushdown(k,l,r,mid);
        if(L<=mid)change(k<<1,l,mid,L,R,val);
        if(R>mid)change((k<<1)|1,mid+1,r,L,R,val);
        sum[k]=(sum[k<<1]+sum[(k<<1)|1])%mod;
    }
    void change1(int x,int y,int val){
        while(top[x]!=top[y]){
    		if(deep[top[x]]<deep[top[y]])swap(x,y);
    		change(1,1,seg[0],seg[top[x]],seg[x],val);
    		x=fa[top[x]];
        }
        if(deep[x]>deep[y])swap(x,y);
        change(1,1,seg[0],seg[x],seg[y],val);
    }
    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);
        int res=0;
        if(L<=mid)res=(res+query(k<<1,l,mid,L,R))%mod;
        if(R>mid)res=(res+query((k<<1)|1,mid+1,r,L,R))%mod;
        return res%mod;
    }
    void ask1(int x,int y){
        int ans=0;
        while(top[x]!=top[y]){
    		if(deep[top[x]]<deep[top[y]])swap(x,y);
    		ans=(ans+query(1,1,seg[0],seg[top[x]],seg[x]))%mod;
    		x=fa[top[x]];
        }
        if(deep[x]>deep[y])swap(x,y);
        ans=(ans+query(1,1,seg[0],seg[x],seg[y]))%mod;
        printf("%d
    ",ans%mod);
    }
    void change2(int x,int val){change(1,1,seg[0],seg[x],seg[x]+size[x]-1,val);}
    void ask2(int x){
        int ans=0;
        ans=query(1,1,seg[0],seg[x],seg[x]+size[x]-1)%mod;
        printf("%d
    ",ans%mod);
    }
    int main(){
        n=read();m=read();root=read();mod=read();
        for(int i=1;i<=n;i++)val[i]=read()%mod;
        for(int i=1;i<n;i++)add_edge(read(),read());
        rev[1]=root;seg[0]=1;seg[root]=1;top[root]=root;
        dfs1(root,0);dfs2(root,0);
        build(1,1,seg[0]);
        int x,y,z;
        while(m--){
    		int opt=read();
    		if(opt==1){x=read();y=read();z=read();change1(x,y,z);continue;}
    		if(opt==2){x=read();y=read();ask1(x,y);continue;}
    		if(opt==3){x=read();y=read();change2(x,y);continue;}
    		if(opt==4){x=read();ask2(x);continue;}
        }
        return 0;
    }
    
    
  • 相关阅读:
    libv4l 库【转】
    Leap Motion颠覆操控体验的超精致手势追踪技术【转】
    嵌入式Linux下Camera编程--V4L2【转】
    C语言高级应用---操作linux下V4L2摄像头应用程序【转】
    通过摄像头设备采集一帧数据的例子程序(完整版)【转】
    V4L2 camera 驱动 capture测试程序【转】
    v4l2 spec 中文 Ch01【转】
    Video for Linux Two API Specification Revision 2.6.32【转】
    Video for Linux Two API Specification revision0.24【转】
    OpenCV实践之路——人脸检测(C++/Python) 【转】
  • 原文地址:https://www.cnblogs.com/PPXppx/p/10478929.html
Copyright © 2011-2022 走看看