题目描述

毛毛虫经过及时的变形,最终逃过的一劫,离开了菜妈的菜园。 毛毛虫经过千山万水,历尽千辛万苦,最后来到了小小的绍兴一中的校园里。

爬啊爬~爬啊爬毛毛虫爬到了一颗小小的“毛景树”下面,发现树上长着他最爱吃的毛毛果~ “毛景树”上有N个节点和N-1条树枝,但节点上是没有毛毛果的,毛毛果都是长在树枝上的。但是这棵“毛景树”有着神奇的魔力,他能改变树枝上毛毛果的个数:

  • Change k w:将第k条树枝上毛毛果的个数改变为w个。
  • Cover u v w:将节点u与节点v之间的树枝上毛毛果的个数都改变为w个。
  • Add u v w:将节点u与节点v之间的树枝上毛毛果的个数都增加w个。 由于毛毛虫很贪,于是他会有如下询问:
  • Max u v:询问节点u与节点v之间树枝上毛毛果个数最多有多少个。

解析

毒瘤题。

首先这是个裸的边树剖。一般来说,我们平时做的树剖都是对一系列点权进行操作,而这题要求我们对一系列边权进行操作。

点权转化为边权,是一件很简单的事情。我们只需把每个节点\(x\)\(father(x)\)之间的边权存在\(x\)的点权上就行了,显然这是不影响正确性的。那么对于一个对\(s\sim t\)的路径操作,我们就只用在原先统计点权的基础上减去\(s,t\)的LCA的点权就可以了。而树剖给了我们一个方便的优化,统计答案时,最后一步一定有\(top[x]=top[y]\)(设\(deep[x]<deep[y]\)),而且它们处于同一条重链上,那么根据树剖的编号规则,\(lca(s,t)\)正是此时的\(x\),我们统计\(calc(id[x]+1,id[y])\)\(id[x]\)为树剖后\(x\)的编号)即可。


这一题的毒瘤之处在于区间加和区间覆盖之间的优先级。显然,将区间全部修改为同一个值的优先级大于区间加。

我们需要这么搞pushdown:

inline void pushdown(int p)
{
    if(t[p].rem!=-1){//区间覆盖为某一值的tag
        t[p<<1].max=t[p].rem;
        t[p<<1|1].max=t[p].rem;
        t[p<<1].rem=t[p].rem;
        t[p<<1|1].rem=t[p].rem;
        t[p<<1].add=0;t[p<<1|1].add=0;
        t[p].rem=-1;
    }
    if(t[p].add){//区间加的tag
        t[p<<1].max+=t[p].add;
        t[p<<1|1].max+=t[p].add;
        t[p<<1].add+=t[p].add;
        t[p<<1|1].add+=t[p].add;
        t[p].add=0;
    }
}

参考代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<string>
#include<cstdlib>
#include<queue>
#include<vector>
#define INF 0x3f3f3f3f
#define PI acos(-1.0)
#define N 100010
#define MOD 2520
#define E 1e-12
using namespace std;
inline int read()
{
    int f=1,x=0;char c=getchar();
    while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
    while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
    return x*f;
}
struct rec{
    int ver,next,edge;
}g[N<<1];
int head[N],tot,n,cnt;
inline void add(int x,int y,int val)
{
    g[++tot].ver=y,g[tot].edge=val;
    g[tot].next=head[x],head[x]=tot;
}
struct tree{
    int l,r;
    int max,add,rem;
}t[N<<2];
int top[N],id[N],size[N],son[N],fa[N],dep[N],w[N],wt[N];
struct node{
    int u,v;
}a[N];
inline void pushup(int p){t[p].max=max(t[p<<1].max,t[p<<1|1].max);}
inline void pushdown(int p)
{
    if(t[p].rem!=-1){
        t[p<<1].max=t[p].rem;
        t[p<<1|1].max=t[p].rem;
        t[p<<1].rem=t[p].rem;
        t[p<<1|1].rem=t[p].rem;
        t[p<<1].add=0;t[p<<1|1].add=0;
        t[p].rem=-1;
    }
    if(t[p].add){
        t[p<<1].max+=t[p].add;
        t[p<<1|1].max+=t[p].add;
        t[p<<1].add+=t[p].add;
        t[p<<1|1].add+=t[p].add;
        t[p].add=0;
    }
}
inline void build(int p,int l,int r)
{
    t[p].l=l,t[p].r=r;t[p].rem=-1;
    if(l==r){t[p].max=w[l];return;}
    int mid=(l+r)>>1;
    build(p<<1,l,mid);
    build(p<<1|1,mid+1,r);
    pushup(p);
}
inline void change(int p,int l,int r,int val)
{
    if(l<=t[p].l&&t[p].r<=r){
        t[p].max+=val;
        t[p].add+=val;
        return;
    }
    pushdown(p);
    int mid=(t[p].l+t[p].r)>>1;
    if(l<=mid) change(p<<1,l,r,val);
    if(r>mid) change(p<<1|1,l,r,val);
    pushup(p);
}
inline void Cover(int p,int l,int r,int val)
{
    if(l<=t[p].l&&t[p].r<=r){
        t[p].max=val;
        t[p].rem=val;t[p].add=0;
        return;
    }
    pushdown(p);
    int mid=(t[p].l+t[p].r)>>1;
    if(l<=mid) Cover(p<<1,l,r,val);
    if(r>mid) Cover(p<<1|1,l,r,val);
    pushup(p);
}
inline int query(int p,int l,int r)
{
    if(l<=t[p].l&&t[p].r<=r) return t[p].max;
    pushdown(p);
    int mid=(t[p].l+t[p].r)>>1;
    int val=0;
    if(l<=mid) val=max(val,query(p<<1,l,r));
    if(r>mid) val=max(val,query(p<<1|1,l,r));
    return val;
}
inline void dfs1(int x,int f,int deep)
{
    size[x]=1,fa[x]=f,dep[x]=deep;
    int maxson=-1;
    for(int i=head[x];i;i=g[i].next){
        int y=g[i].ver,z=g[i].edge;
        if(y==f) continue;
        wt[y]=z;
        dfs1(y,x,deep+1);
        size[x]+=size[y];
        if(maxson<size[y]) maxson=size[y],son[x]=y;
    }
}
inline void dfs2(int x,int topf)
{
    id[x]=++cnt,top[x]=topf,w[cnt]=wt[x];;
    if(!son[x]) return;
    dfs2(son[x],topf);
    for(int i=head[x];i;i=g[i].next){
        int y=g[i].ver;
        if(y==fa[x]||y==son[x]) continue;
        dfs2(y,y);
    }
}
inline void ichange(int x,int y,int val)
{
    while(top[x]!=top[y]){
        if(dep[top[x]]<dep[top[y]]) swap(x,y);
        change(1,id[top[x]],id[x],val);
        x=fa[top[x]];
    }
    if(dep[x]>dep[y]) swap(x,y);
    change(1,id[x]+1,id[y],val);
}
inline int iquery(int x,int y)
{
    int res=0;
    while(top[x]!=top[y]){
        if(dep[top[x]]<dep[top[y]]) swap(x,y);
        res=max(res,query(1,id[top[x]],id[x]));
        x=fa[top[x]];
    }
    if(dep[x]>dep[y]) swap(x,y);
    res=max(res,query(1,id[x]+1,id[y]));
    return res;
}
inline void cover(int x,int y,int val)
{
    while(top[x]!=top[y]){
        if(dep[top[x]]<dep[top[y]]) swap(x,y);
        Cover(1,id[top[x]],id[x],val);
        x=fa[top[x]];
    }
    if(dep[x]>dep[y]) swap(x,y);
    Cover(1,id[x]+1,id[y],val);
}
int main()
{
    n=read();
    for(int i=1;i<n;++i){
        a[i].u=read(),a[i].v=read();
        int z=read();
        add(a[i].u,a[i].v,z),add(a[i].v,a[i].u,z);
    }
    dfs1(1,0,1);
    dfs2(1,1);
    build(1,1,n);
    char op[10];
    int x,y,z;
    while(~scanf("%s",op)){
        if(op[0]=='S') return 0;
        if(op[0]=='M'){
            x=read(),y=read();
            printf("%d\n",iquery(x,y));
        }
        if(op[0]=='A'){
            x=read(),y=read(),z=read();
            ichange(x,y,z);
        }
        if(op[0]=='C'){
            if(op[1]=='h'){
                x=read(),z=read();
                cover(a[x].u,a[x].v,z);
            }
            else{
                x=read(),y=read(),z=read();
                cover(x,y,z);
            }
        }
    }
    return 0;
}
01-25 13:30