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\n",query_path(x,y));
        }else if(cas==3){
            int x=read(),val=read();
            update_subtree(x,val);
        }else{
            int x=read();
            printf("%d\n",query_subtree(x));
        }
    }
    return 0;
}


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

posted @ 2018-11-08 10:51  skl_win  阅读(182)  评论(0编辑  收藏  举报
Live2D