树剖——【模板】树链剖分

题目来源

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;  
}  


#include <cstdio> #include <iostream> #include <vector> #define N 30003 #define INF 2147483647 using namespace std; int n,f[N][20],dep[N],siz[N],son[N],top[N],tot,pos[N],w[N]; int Max[N*4],Sum[N*4]; vector <int> to[N]; void dfs1(int x){ siz[x]=1; int sz=to[x].size(); for(int i=0;i<sz;++i){ int y=to[x][i]; if(y==f[x][0])continue; f[y][0]=x; dep[y]=dep[x]+1; dfs1(y); siz[x]+=siz[y]; if(siz[y]>siz[son[x]])son[x]=y; } } void dfs2(int x,int root){ top[x]=root; pos[x]=++tot; if(son[x])dfs2(son[x],root); int sz=to[x].size(); for(int i=0;i<sz;++i){ int y=to[x][i]; if(y==f[x][0] || y==son[x])continue; dfs2(y,y); } } void update(int k,int l,int r,int P,int V){ if(l==r){ Max[k]=Sum[k]=V; return; } int mid=(l+r)>>1; if(P<=mid)update(k*2,l,mid,P,V); else update(k*2+1,mid+1,r,P,V); Max[k]=max(Max[k*2],Max[k*2+1]); Sum[k]=Sum[k*2]+Sum[k*2+1]; } void up(int &x,int goal){ for(int i=15;i>=0;--i) if(dep[f[x][i]]>=goal)x=f[x][i]; } int lca(int x,int y){ if(dep[x]>dep[y])up(x,dep[y]); if(dep[x]<dep[y])up(y,dep[x]); if(x==y)return x; for(int i=15;i>=0;--i) if(f[x][i]!=f[y][i])x=f[x][i],y=f[y][i]; return f[x][0]; } int getm(int k,int l,int r,int L,int R){ if(L<=l && r<=R)return Max[k]; int res=-INF,mid=(l+r)>>1; if(L<=mid)res=max(res,getm(k*2,l,mid,L,R)); if(R>mid)res=max(res,getm(k*2+1,mid+1,r,L,R)); return res; } int gets(int k,int l,int r,int L,int R){ if(L<=l && r<=R)return Sum[k]; int res=0,mid=(l+r)>>1; if(L<=mid)res+=gets(k*2,l,mid,L,R); if(R>mid)res+=gets(k*2+1,mid+1,r,L,R); return res; } int main(){ scanf("%d",&n); for(int i=1,a,b;i<n;++i){ scanf("%d%d",&a,&b); to[a].push_back(b); to[b].push_back(a); } dep[1]=1; dfs1(1); dfs2(1,1); for(int i=1;i<=15;++i) for(int j=1;j<=n;++j)f[j][i]=f[f[j][i-1]][i-1]; for(int i=1;i<=n;++i){ scanf("%d",&w[i]); update(1,1,n,pos[i],w[i]); } int q; scanf("%d",&q); while(q--){ char s[10]; int u,v,t; scanf("%s",s); if(s[1]=='H'){ scanf("%d%d",&u,&t); w[u]=t; update(1,1,n,pos[u],t); } if(s[1]=='M'){ scanf("%d%d",&u,&v); int ans=-INF,t=lca(u,v); for(int i=u;i;i=f[top[i]][0]) if(dep[t]<dep[top[i]]) ans=max(ans,getm(1,1,n,pos[top[i]],pos[i])); else{ ans=max(ans,getm(1,1,n,pos[t],pos[i])); break; } for(int i=v;i;i=f[top[i]][0]) if(dep[t]<dep[top[i]]) ans=max(ans,getm(1,1,n,pos[top[i]],pos[i])); else{ ans=max(ans,getm(1,1,n,pos[t],pos[i])); break; } printf("%d\n",ans); } if(s[1]=='S'){ scanf("%d%d",&u,&v); int ans=0,t=lca(u,v); for(int i=u;i;i=f[top[i]][0]) if(dep[t]<dep[top[i]]) ans+=gets(1,1,n,pos[top[i]],pos[i]); else{ ans+=gets(1,1,n,pos[t],pos[i]); break; } for(int i=v;i;i=f[top[i]][0]) if(dep[t]<dep[top[i]]) ans+=gets(1,1,n,pos[top[i]],pos[i]); else{ ans+=gets(1,1,n,pos[t],pos[i]); break; } printf("%d\n",ans-w[t]); } } }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值