送你個樹鏈剖分板子(洛谷P3384 【模板】輕重鏈剖分)

送你個樹鏈剖分板子(洛谷P3384 【模板】輕重鏈剖分)

題目鏈接

碼量還是差了點,昨天一個錯誤找了一晚上都沒找到,這塊終於算入了個門吧

#include<bits/stdc++.h>
#define lowbit(x) x&(-x)
#define ll long long
#define inf 0x3f3f3f3f
using namespace std;
const int maxn=1e5+5;
struct Edge{
    int to,nxt;
}edge[maxn<<2];   //無向圖所以得乘4
int head[maxn],tot;
struct node{
    int l,r,v,len,lazy;
}tree[maxn<<2];
int n,m,root,mod;  //見題意
int dep[maxn];    //當前結點的深度
int siz[maxn];    //當前結點爲根的子樹結點個數和
int id[maxn];     //dfs序表示的新編號
int rk[maxn];     //dfs序編號對應在樹的結點
int fa[maxn];    //當前結點的父親
int son[maxn];   //保存重兒子
int top[maxn];   //重鏈的頂點
int cnt;
int a[maxn];    //初始結點的值

/**以下---向前星操作*/
void init(){
    memset(head,-1,sizeof(head));
    tot=0;
}
void add(int u,int v){
    edge[++tot].to=v;
    edge[tot].nxt=head[u];
    head[u]=tot;
}
/**以上---向前星操作*/

/**以下---線段樹操作*/
void build(int now,int l,int r){
    tree[now].l=l,tree[now].r=r,tree[now].len=r-l+1,tree[now].lazy=0;
    if(l==r){
        tree[now].v=rk[l];
        return ;
    }
    int mid=(l+r)>>1;
    build(now<<1,l,mid);
    build((now<<1)+1,mid+1,r);
    tree[now].v=(tree[now<<1].v+tree[(now<<1)+1].v)%mod;
}
void push_down(int now){
    if(tree[now].lazy){
        tree[now<<1].lazy+=tree[now].lazy;
        tree[now<<1].lazy%=mod;
        tree[(now<<1)+1].lazy+=tree[now].lazy;
        tree[(now<<1)+1].lazy%=mod;
        tree[now<<1].v+=(tree[now<<1].len*tree[now].lazy);
        tree[(now<<1)].v%=mod;
        tree[(now<<1)+1].v+=(tree[(now<<1)+1].len*tree[now].lazy);
        tree[(now<<1)+1].v%=mod;
        tree[now].lazy=0;
    }
}
void update(int now,int l,int r,int val){
    if(tree[now].l>=l&&tree[now].r<=r){
        tree[now].v+=val*tree[now].len;
        tree[now].v%=mod;
        tree[now].lazy+=val;
        tree[now].lazy%=mod;
        return ;
    }
    if(tree[now].l>r||tree[now].r<l)
        return ;
    if(tree[now].lazy){
        push_down(now);
    }
    update(now<<1,l,r,val);
    update((now<<1)+1,l,r,val);
    tree[now].v=(tree[now<<1].v+tree[(now<<1)+1].v)%mod;
}
int query(int now,int l,int r){
    if(tree[now].l>=l&&tree[now].r<=r){
        return tree[now].v;
    }
    if(tree[now].l>r||tree[now].r<l)
        return 0;
    if(tree[now].lazy){
        push_down(now);
    }
    return (query(now<<1,l,r)+query((now<<1)+1,l,r))%mod;
}
/**以上---線段樹操作*/

/**以下---兩次dfs*/
void dfs1(int now,int father,int depth){
    //標記每個結點的父親,深度,子樹的結點數,以及每個結點的重兒子
    dep[now]=depth,fa[now]=father,siz[now]=1;
    int maxnum=-1;
    for(int i=head[now];i!=-1;i=edge[i].nxt){
        int v=edge[i].to;
        if(v==father)
            continue;
        dfs1(v,now,depth+1);
        siz[now]+=siz[v];
        if(siz[v]>maxnum){
            maxnum=siz[v];
            son[now]=v;
        }
    }
}
void dfs2(int now,int nowt){
    //連接重鏈,並且根據重鏈標註出dfs序,方便使用數據結構維護
    top[now]=nowt;
    id[now]=++cnt;
    rk[cnt]=a[now];
    if(son[now]==0){
        return ;
    }
    dfs2(son[now],nowt);
    for(int i=head[now];i!=-1;i=edge[i].nxt){
        int v=edge[i].to;
        if(v!=son[now]&&v!=fa[now])
            dfs2(v,v);
    }
}
/**以上---兩次dfs*/

void updatePath(int x,int y,int val){
   while(top[x]!=top[y]){
        if(dep[top[x]]<dep[top[y]])
            swap(x,y);
        update(1,id[top[x]],id[x],val);
        x=fa[top[x]];
   }
   if(dep[x]>dep[y])
        swap(x,y);
   update(1,id[x],id[y],val);
}
int queryPathSum(int x,int y){
    int ans=0;
    while(top[x]!=top[y]){
        if(dep[top[x]]<dep[top[y]])
            swap(x,y);
        ans=(ans+query(1,id[top[x]],id[x]))%mod;
        x=fa[top[x]];
    }
    if(dep[x]>dep[y])
        swap(x,y);
    ans=(ans+query(1,id[x],id[y]))%mod;
    return ans;
}
int main(){
    scanf("%d%d%d%d",&n,&m,&root,&mod);
    for(int i=1;i<=n;i++){
        scanf("%d",&a[i]);
    }
    init();   //向前星初始化
    int u,v;
    for(int i=1;i<n;i++){
        scanf("%d%d",&u,&v);
        add(u,v),add(v,u);
    }
    cnt=0;   //新編號
    dfs1(root,0,1);
    dfs2(root,root);
    build(1,1,n);

    while(m--){
        int flag,x,y,z;
        scanf("%d",&flag);
        if(flag==1){
            scanf("%d%d%d",&x,&y,&z);
            updatePath(x,y,z);
        }
        else if(flag==2){
            scanf("%d%d",&x,&y);
            printf("%d\n",queryPathSum(x,y));
        }
        else if(flag==3){
            scanf("%d%d",&x,&y);
            y%=mod;
            update(1,id[x],siz[x]+id[x]-1,y);
        }
        else{
            scanf("%d",&x);
            printf("%d\n",query(1,id[x],id[x]+siz[x]-1));
        }
    }
    return 0;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章