树链剖分_[模板]

题目链接洛谷P3374 【模板】轻重链剖分
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cmath>
#include<cstring>
using namespace std;
struct node{
    int a,lz;
}tree[200000];
int v[200000],w[200000],next[200000],last[200000],num,nw[200000],id[200000];
int son[200000],top[200000],deep[200000],size[200000],fa[200000];
int n,m,r,p;
void add(int x,int y)
{
    num++;
    v[num]=y;
    next[num]=last[x];
    last[x]=num;
}
void dfs1(int root,int ff,int de)
{
    fa[root]=ff;
    deep[root]=de;
    size[root]=1;
    int maxson=0;
    for(int i=last[root];i;i=next[i])
    {
        if(deep[v[i]]!=0) continue;
        dfs1(v[i],root,de+1);
        size[root]+=size[v[i]];
        if(size[v[i]]>maxson) son[root]=v[i];
    }
}
void dfs2(int root,int topp)
{
    num++;
    top[root]=topp;
    nw[num]=w[root];
    id[root]=num;
    if(son[root]!=0) dfs2(son[root],topp);
    for(int i=last[root];i;i=next[i])
    {
        if (top[v[i]]!=0) continue;
        dfs2(v[i],v[i]);
    }
}
void buildtree(int root,int l,int r)
{
    if(l>r) return;
    if(l==r){ tree[root].a=nw[l]; return;}
    int mid=(r+l)/2;
    buildtree(root*2,l,mid);
    buildtree(root*2+1,mid+1,r);
    tree[root].a=(tree[root*2].a+tree[root*2+1].a)%p;
}
void putdown(int root,int l,int r)
{
    if(tree[root].lz!=0)
    {
        tree[root*2].lz+=tree[root].lz;
        tree[root*2+1].lz+=tree[root].lz;
        int mid=(l+r)/2;
        tree[root*2].a=(tree[root*2].a%p+tree[root].lz*(mid-l+1)%p)%p;
        tree[root*2+1].a=(tree[root*2+1].a%p+tree[root].lz*(r-mid)%p)%p;
        tree[root].lz=0;
    }
    return; 
}
void treechange(int root,int l,int r,int s,int t,int ad)
{
    if(s<=l && r<=t) 
      {
            tree[root].lz+=ad;
            tree[root].a=(tree[root].a+(r-l+1)*ad)%p;
            return;
      }
    putdown(root,l,r);
    int mid=(l+r)/2;
    if (mid>=s)
        treechange(root*2,l,mid,s,t,ad);
    if (mid+1<=t)
        treechange(root*2+1,mid+1,r,s,t,ad);
    tree[root].a=(tree[root*2].a+tree[root*2+1].a)%p;
    return;
}
int treefind(int root,int l,int r,int s,int t)
{
    if(l>=s && r<=t)
        return tree[root].a;
    if(r<s || l>t)  return 0;
    putdown(root,l,r);
    int ans=0,mid=(l+r)/2;
    if(mid>=s)  ans=(ans%p+treefind(root*2,l,mid,s,t)%p)%p;
    if(mid+1<=t)  ans=(ans%p+treefind(root*2+1,mid+1,r,s,t)%p)%p;
    
    return ans%p;
}
void change1(int x,int y,int z)
{
    while(top[x]!=top[y])
    {
        if(deep[top[x]]<deep[top[y]]) swap(x,y);
        treechange(1,1,n,id[top[x]],id[x],z);
        x=fa[top[x]];
    }
    if(deep[x]<deep[y]) swap(x,y);
    treechange(1,1,n,id[y],id[x],z);
}
int find1(int x,int y,int z)
{
    int ans=0;
    while(top[x]!=top[y])
    {
        if(deep[top[x]]<deep[top[y]]) swap(x,y);
        ans=(ans+treefind(1,1,n,id[top[x]],id[x]))%p;
        x=fa[top[x]];
    }
    if(deep[x]<deep[y]) swap(x,y);
    ans=(ans+treefind(1,1,n,id[y],id[x]))%p;
    return ans;
}
void change2(int x,int z){
    treechange(1,1,n,id[x],id[x]+size[x]-1,z);
}
int find2(int x){
    int ans=0;
    ans=treefind(1,1,n,id[x],id[x]+size[x]-1)%p;
    return ans;
}
int main()
{
    scanf("%d%d%d%d",&n,&m,&r,&p);
    for(int i=1;i<=n;i++)
      scanf("%d",&w[i]);
    for(int i=1;i<=n-1;i++)
     {
        int x,y;
        scanf("%d%d",&x,&y);
        add(x,y);
        add(y,x);
     }
    dfs1(r,0,1);
    num=0;
    dfs2(r,r);
    buildtree(1,1,n);
    for(int i=1;i<=m;i++)
     {
        int t,x,y,z;
        scanf("%d",&t);
        if(t==1)
        {
            scanf("%d%d%d",&x,&y,&z);
            change1(x,y,z);
        }
        if(t==2)
        {
            scanf("%d%d",&x,&y);
            int ans=find1(x,y,z);
            printf("%d\n",ans%p);
        }
        if(t==3)
        {
            scanf("%d%d",&x,&z);
            change2(x,z);
        }
        if(t==4)
        {
            scanf("%d",&x);
            int ans=find2(x);
            printf("%d\n",ans%p);
        }        
     }
}

 

 
posted @ 2020-10-29 21:43  Li_yxxx  阅读(75)  评论(0)    收藏  举报