P3384 輕重鏈剖分(樹剖模板)

題目描述


如題,已知一棵包含 NN 個結點的樹(連通且無環),每個節點上包含一個數值,需要支持以下操作:

操作 1: 格式: 1 x y z 表示將樹從 x 到 y 結點最短路徑上所有節點的值都加上 z。

操作 2: 格式:2 x y 表示求樹從 x 到 y 結點最短路徑上所有節點的值之和。

操作 3: 格式: 3 x z 表示將以 x 爲根節點的子樹內所有節點值都加上 z。

操作 4: 格式: 4 x 表示求以 x 爲根節點的子樹內所有節點值之和

輸入格式)

第一行包含 4 個正整數 N,M,R,P,分別表示樹的結點個數、操作個數、根節點序號和取模數(即所有的輸出結果均對此取模)。

接下來一行包含 N 個非負整數,分別依次表示各個節點上初始的數值。

接下來 N−1 行每行包含兩個整數 x,y,表示點 x 和點 y 之間連有一條邊(保證無環且連通)。

接下來 MM 行每行包含若干個正整數,每行表示一個操作,格式如下:

操作 1:1 x y z;

操作 2: 2 x y;

操作 3:3 x z;

操作 4: 4 x。

輸出格式
輸出包含若干行,分別依次表示每個操作2 或操作 4 所得的結果(對 P 取模)。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int mx=1e5+10;
const int MAXN=2*1e6+10;
const double PI=cos(-1.0);
int dep[mx],top[mx],w[mx],son[mx],id[mx],siz[mx],fa[mx],res=0,cnt=0,a[mx];
int qr[mx<<2],laz[mx<<2];
int n,m,r,p;
vector<int>G[mx];
#define Temp template<typename T>
inline char nc()
{
    static char buf[MAXN],*p1=buf,*p2=buf;
    return p1==p2&&(p2=(p1=buf)+fread(buf,1,MAXN,stdin),p1==p2)?EOF:*p1++;
}
inline int read()
{
    char c=nc();int x=0,f=1;
    while(c<'0'||c>'9'){if(c=='-')f=-1;c=nc();}
    while(c>='0'&&c<='9'){x=x*10+c-'0',c=nc();}
    return x*f;
}
#define mid ((l+r)>>1)
#define lson rt<<1,l,mid
#define rson rt<<1|1,mid+1,r
#define len (r-l+1)
inline void pushdown(int rt,int lenn)
{
    laz[rt<<1]+=laz[rt];
    laz[rt<<1|1]+=laz[rt];
    qr[rt<<1]+=laz[rt]*(lenn-(lenn>>1));
    qr[rt<<1|1]+=laz[rt]*(lenn>>1);
    qr[rt<<1]%=p;
    qr[rt<<1|1]%=p;
    laz[rt]=0;
}
inline void build(int rt,int l,int r)
{
    if(l==r)
    {
        qr[rt]=w[l];
        if(qr[rt]>p) qr[rt]%=p;
        return ;
    }
    build(lson);
    build(rson);
    qr[rt]=(qr[rt<<1]+qr[rt<<1|1])%p;
}
inline void query(int rt,int l,int r,int L,int R){
    if(L<=l&&r<=R){res+=qr[rt];res%=p;return;}
    else{
        if(laz[rt])pushdown(rt,len);
        if(L<=mid)query(lson,L,R);
        if(R>mid)query(rson,L,R);
    }
}
inline void updata(int rt,int l,int r,int L,int R,int k)
{
    if(L<=l&&r<=R)
    {
        laz[rt]+=k;
        qr[rt]+=k*len;
    }
    else{
        if(laz[rt]) pushdown(rt,len);
        if(L<=mid) updata(lson,L,R,k);
        if(R>mid) updata(rson,L,R,k);
        qr[rt]=(qr[rt<<1]+qr[rt<<1|1])%p;
    }
}
inline int qrange(int x,int y)
{
    int ans=0;
    while(top[x]!=top[y])
    {
        if(dep[top[x]]<dep[top[y]]) swap(x,y);
        res=0;
        query(1,1,n,id[top[x]],id[x]);
        ans=(ans+res)%p;
        x=fa[top[x]];
    }
    if(dep[x]>dep[y]) swap(x,y);res=0;
    query(1,1,n,id[x],id[y]);
    ans+=res;
    return ans%p;
}
inline int upqrange(int x,int y,int k)
{
    k%=p;
    while(top[x]!=top[y])
    {
        if(dep[top[x]]<dep[top[y]]) swap(x,y);
        updata(1,1,n,id[top[x]],id[x],k);
        x=fa[top[x]];
    }
    if(dep[x]>dep[y]) swap(x,y);
    updata(1,1,n,id[x],id[y],k);

}
inline void dfs(int u,int fath,int deep)
{
     fa[u]=fath;
     dep[u]=deep;
     siz[u]=1;
     int maxone=-1;
     for(int i=0;i<G[u].size();i++)
     {
         int to=G[u][i];
         if(to==fath) continue;
         dfs(to,u,deep+1);
         siz[u]+=siz[to];
         if(siz[to]>maxone)
         {
             maxone=siz[to];
             son[u]=to;
         }
     }
}
inline void dfs2(int x,int fst)
{
    top[x]=fst;
    id[x]=++cnt;
    w[cnt]=a[x];
    if(!son[x]) return;
    dfs2(son[x],fst);
    for(register int i=0;i<G[x].size();i++)
    {
        int v=G[x][i];
        if(v==fa[x]||v==son[x]) continue;
        dfs2(v,v);
    }
}
int main()
{
    scanf("%d%d%d%d",&n,&m,&r,&p);
//    n=read(),m=read(),r=read(),p=read();
    for(int i=1;i<=n;i++) scanf("%d",&a[i]);

    for(int i=1,x,y;i<n;i++)
    {
        scanf("%d%d",&x,&y);
//        x=read();y=read();
        G[x].push_back(y);
        G[y].push_back(x);
    }
    dfs(r,0,1);
    dfs2(r,r);
    build(1,1,n);
    for(int i=1,x,y,z,q;i<=m;i++)
    {
        scanf("%d",&q);
        if(q==1)
        {
            scanf("%d%d%d",&x,&y,&z);
//            x=read();y=read();z=read();
            upqrange(x,y,z);
        }
        else if(q==2)
        {
           scanf("%d%d",&x,&y);
            printf("%d\n",qrange(x,y));
        }
        else if(q==3)
        {
            scanf("%d%d",&x,&z);
           // x=read();z=read();
            updata(1,1,n,id[x],id[x]+siz[x]-1,z);
        }
        else
        {
            scanf("%d",&x);
            res=0;query(1,1,n,id[x],id[x]+siz[x]-1);
            printf("%d\n",res);
        }
    }
   return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章