天天看點

樹剖——【模闆】樹鍊剖分題目來源代碼(C++)

題目來源

P3384 【模闆】樹鍊剖分

https://www.luogu.org/problemnew/show/3384

代碼(C++)

#include <cstdio>
#include <bitset>
#define ll long long
#define N 100010
#define M 200010
using namespace std;
struct tree{ll x,y,sum,lazy;tree *l,*r;};
tree *root,*null=new tree();
ll n,m,s,p,u,v,w,x,y,z,cnt=0,t[N],wei[N];
bitset<N> g;	ll c,ma[N],nt[N];
ll he[N],en[M],ne[M],si[N],hs[N],fa[N],de[N];
inline void add();
inline ll read();
tree *build(ll st,ll en);
void dfs2(ll pos,ll top);
void dfs1(ll pos,ll depth);
ll ask(ll st,ll en,tree *pos);
inline ll lca2(ll x,ll y);
inline void lca1(ll x,ll y,ll num);
void change(ll st,ll en,tree *pos,ll num);
int main()
{
    n=read(); m=read(); s=read(); p=read();
    for(ll i=1;i<=n;++i)
        wei[i]=read();
    for(ll i=1;i<n;++i)
        u=read(),v=read(),add();
    dfs1(s,1); g=0; cnt=0; dfs2(s,s);
    root=build(1,n);
    for(ll i=1;i<=m;++i)
    {
        c=read();
        switch(c)
        {
            case 1:
                x=read(); y=read(); z=read();
                lca1(x,y,z);
                break;
            case 2:
                x=read(); y=read();
                printf("%lld\n",lca2(x,y));
                break;
            case 3:
                x=read(); y=read();
                change(ma[x],ma[x]+si[x]-1,root,y);
                break;
            case 4:
                x=read();
                printf("%lld\n",ask(ma[x],ma[x]+si[x]-1,root)%p);
                break;
        }
    }
    return 0;
}
inline ll lca2(ll x,ll y)
{
    ll res=0;
    while(t[x]!=t[y])
    {
        if(de[t[x]]<de[t[y]]){ll z=x; x=y; y=z;}
        res+=ask(ma[t[x]],ma[x],root);	res%=p;
        x=fa[t[x]];
    }
    if(de[x]>de[y]){ll z=x; x=y; y=z;}
    res+=ask(ma[x],ma[y],root);
    return res%p;
}
inline void lca1(ll x,ll y,ll num)
{
    while(t[x]!=t[y])
    {
        if(de[t[x]]<de[t[y]]){ll z=x; x=y; y=z;}
        change(ma[t[x]],ma[x],root,num);
        x=fa[t[x]];
    }
    if(de[x]>de[y]){ll z=x; x=y; y=z;}
    change(ma[x],ma[y],root,num);
    return ;
}
void change(ll st,ll en,tree *pos,ll num)
{
    if(pos->lazy&&pos->l!=null)
    {
        pos->l->sum+=(pos->l->y-pos->l->x+1)*pos->lazy;
        pos->r->sum+=(pos->r->y-pos->r->x+1)*pos->lazy;
        pos->l->lazy+=pos->lazy;
        pos->r->lazy+=pos->lazy;
        pos->lazy=0;
    }
    pos->sum+=(en-st+1)*num;
    if(pos->x==st&&pos->y==en)
    {
        pos->lazy+=num;
        return ;
    }
    if(en<=pos->l->y)
        change(st,en,pos->l,num);
    else if(st>=pos->r->x)
        change(st,en,pos->r,num);
    else
        change(st,pos->l->y,pos->l,num),
        change(pos->r->x,en,pos->r,num);
    return ;
}
ll ask(ll st,ll en,tree *pos)
{
    if(pos->lazy&&pos->l!=null)
    {
        pos->l->sum+=(pos->l->y-pos->l->x+1)*pos->lazy;
        pos->r->sum+=(pos->r->y-pos->r->x+1)*pos->lazy;
        pos->l->lazy+=pos->lazy;
        pos->r->lazy+=pos->lazy;
        pos->lazy=0;
    }
    if(pos->x==st&&pos->y==en)
        return pos->sum%p;
    if(en<=pos->l->y)
        return ask(st,en,pos->l);
    if(st>=pos->r->x)
        return ask(st,en,pos->r);
    ll res=0;
    res+=ask(st,pos->l->y,pos->l);
    res+=ask(pos->r->x,en,pos->r);
    return res%p;
}
tree *build(ll st,ll en)
{
    tree *k=new tree();
    k->x=st;	k->y=en;	k->lazy=0;
    if(st==en)
        k->l=null,k->r=null,k->sum=wei[nt[st]];
    else
        k->l=build(st,(st+en)/2),
        k->r=build((st+en)/2+1,en),
        k->sum=k->l->sum+k->r->sum;
    return k;
}
void dfs2(ll pos,ll top)
{
    g[pos]=1;		t[pos]=top;
    ++cnt;		ma[pos]=cnt;	nt[cnt]=pos;
    if(hs[pos])
        dfs2(hs[pos],top);
    for(ll k=he[pos];k;k=ne[k])
        if(!g[en[k]])
            dfs2(en[k],en[k]);
    return ;
}
void dfs1(ll pos,ll depth)
{
    g[pos]=1; si[pos]=1; de[pos]=depth;
    for(ll k=he[pos];k;k=ne[k])
        if(!g[en[k]])
        {
            dfs1(en[k],depth+1);
            fa[en[k]]=pos;
            si[pos]+=si[en[k]];
            if(si[en[k]]>si[hs[pos]])
                hs[pos]=en[k];
        }
    return ;
}
inline void add()
{
    en[++cnt]=v; ne[cnt]=he[u]; he[u]=cnt;
    en[++cnt]=u; ne[cnt]=he[v]; he[v]=cnt;
}
inline ll read()
{  
    char x=getchar();    ll num=0;  
    while(!(x>=48&&x<=57))  
        x=getchar();  
    while(x>=48&&x<=57)  
        num=num*10+x-48,x=getchar();  
    return num;  
}