树链剖分

#include <cstdio>
#include <algorithm>
#include <cstring>
#include <queue>
#include <cmath>
#include <iostream>
using namespace std;
#define ll long long

const int Maxn=100001;

int n,m,r,p,a[Maxn],x,y,now[Maxn*2],id[Maxn*2],Cnt,topf[Maxn*2],top[Maxn*2];
int head[Maxn*2],next[Maxn*2],to[Maxn*2],cnt,son[Maxn*2],size[Maxn*2],deep[Maxn*2],father[Maxn*2];

struct node
{
    int w;
    int left;
    int right;
    int v;	
}tree[Maxn*4];

void Spread_Tree(int pp)
{
    if(tree[pp].v) {
        tree[pp*2].w+=tree[pp].v*(tree[pp*2].right-tree[pp*2].left+1);
        tree[pp*2+1].w+=tree[pp].v*(tree[pp*2+1].right-tree[pp*2+1].left+1);
        tree[pp*2].v+=tree[pp].v;
        tree[pp*2+1].v+=tree[pp].v;
        tree[pp*2].w%=p;
        tree[pp*2+1].w%=p;
        tree[pp].v=0;
    }
}

void Build_Tree(int index,int l,int r)
{
    tree[index].left=l;
    tree[index].right=r;
    if(l==r) return;
    int mid=(l+r)/2;
    Build_Tree(index*2,l,mid);
    Build_Tree(index*2+1,mid+1,r);	
}

int Insert_Tree(int index)
{
    if(tree[index].left==tree[index].right) {
        tree[index].w=now[tree[index].left]%p;
        return tree[index].w%p;
    }
    tree[index].w=(Insert_Tree(index*2)+Insert_Tree(index*2+1))%p;
    return tree[index].w%p;
}

int Query_Tree(int index,int l,int r)
{
    if(tree[index].left>=l&&tree[index].right<=r) return tree[index].w%p;
    int mid=(tree[index].left+tree[index].right)/2;
    Spread_Tree(index);
    long long ans=0;
    if(l<=mid)
        ans+=Query_Tree(index*2,l,r);
    if(r>mid)
        ans+=Query_Tree(index*2+1,l,r);
    return ans%p;
}

void Change_Tree(int index,int l,int r,int k)
{
    if(tree[index].right<=r&&tree[index].left>=l) {
        tree[index].w+=k*(tree[index].right-tree[index].left+1);
        tree[index].v+=k;
        return;
    }
    Spread_Tree(index);
    int mid=(tree[index].left+tree[index].right)/2;
    if(l<=mid)
        Change_Tree(index*2,l,r,k);
    if(r>mid)
        Change_Tree(index*2+1,l,r,k);
    tree[index].w=(tree[index*2].w+tree[index*2+1].w)%p;
}

void Insert(int u,int v)
{
    ++cnt;
    next[cnt]=head[u];
    head[u]=cnt;
    to[cnt]=v;	
}

void dfs_1(int u,int f)
{
    deep[u]=deep[f]+1;
    size[u]=1;
    father[u]=f;
    for(int i=head[u]; i; i=next[i]) {
        int v=to[i];
        if(v!=f) {
            dfs_1(v,u);
            size[u]+=size[v];
            if(size[v]>size[son[u]]) son[u]=v;	
        }
    }
}

void dfs_2(int u,int topf)
{
    id[u]=++Cnt;
    now[Cnt]=a[u];
    top[u]=topf;
    if(!son[u]) return;
    dfs_2(son[u],topf);
    for(int i=head[u]; i; i=next[i]) {
        int v=to[i];
        if(v==father[u]||v==son[u]) continue;
        dfs_2(v,v);	
    }
}	

int Query_Interval(int x,int y)
{
    int ans=0;
    while(top[x]!=top[y]) {
        if(deep[top[x]]<deep[top[y]]) swap(x,y);
        ans+=(Query_Tree(1,id[top[x]],id[x]));
        ans%=p;	
        x=father[top[x]];
    }
    if(deep[x]>deep[y]) swap(x,y);
    ans+=Query_Tree(1,id[x],id[y]);
    return ans%p;
}	

int Change_Interval(int x,int y,int k)
{
    while(top[x]!=top[y]) {
        if(deep[top[x]]<deep[top[y]]) swap(x,y);
        Change_Tree(1,id[top[x]],id[x],k);
        x=father[top[x]];	
    }
    if(deep[x]>deep[y]) swap(x,y);
    Change_Tree(1,id[x],id[y],k);
}	

void Change_Point(int index,int k)
{
    Change_Tree(1,id[index],id[index]+size[index]-1,k);
}

int Query_Point(int index)
{
    return Query_Tree(1,id[index],id[index]+size[index]-1);	
}

int main()
{
    cin>>n>>m>>r>>p;
    for(int i=1; i<=n; i++)
        cin>>a[i];
    for(int i=1; i<n; i++) {
        cin>>x>>y;
        Insert(x,y);
        Insert(y,x);
    }
    dfs_1(r,0);
    dfs_2(r,r);
    Build_Tree(1,1,n);
    Insert_Tree(1);
    for(int i=1; i<=m; i++) {
        int A,B,C,D;
        cin>>A;
        if(A==1) { cin>>B>>C>>D; Change_Interval(B,C,D); }
        if(A==2) { cin>>B>>C; cout<<Query_Interval(B,C)<<endl; }
        if(A==3) { cin>>B>>C; Change_Point(B,C); }
        if(A==4) { cin>>B; cout<<Query_Point(B)<<endl; }
    }
    return 0;
}
posted @ 2019-07-16 13:36  prestige  阅读(135)  评论(0编辑  收藏  举报