BZOJ 1984 月下“毛景树” 树链剖分+线段树

题意

bzoj好像把这题删了,在洛谷里找的

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

爬啊爬爬啊爬毛毛虫爬到了一颗小小的“毛景树”下面,发现树上长着他最爱吃的毛毛果~ “毛景树”上有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之间树枝上毛毛果个数最多有多少个。

分析

把边权转成点权,然后就是树链剖分裸题了,线段树维护下区间最大值就完事了

Code

#include<bits/stdc++.h>
#define fi first
#define se second
#define pb push_back
#define lson l,mid,p<<1
#define rson mid+1,r,p<<1|1
using namespace std;
typedef long long ll;
const int inf=1e9;
const int maxn=2e5;
int n;
int a[maxn],w[maxn],b[maxn];
typedef pair<int,int> pii;
vector<pii>g[maxn];
int top[maxn],f[maxn],d[maxn],id[maxn],p[maxn],sz[maxn],son[maxn],tot;
int mx[maxn<<2],t1[maxn<<2],t2[maxn<<2],t3[maxn<<2];
void pp(int p){mx[p]=max(mx[p<<1],mx[p<<1|1]);}
void bd(int l,int r,int p){
    t1[p]=-1;
    if(l==r) return mx[p]=a[id[l]],void();
    int mid=l+r>>1;
    bd(lson);bd(rson);pp(p);
}
void pd(int p,int a,int b){
    if(a!=-1){
        mx[p]=a;t1[p]=a;t2[p]=0;
    }mx[p]+=b;t2[p]+=b;
}
void up(int dl,int dr,int l,int r,int p,int k,int op){
    if(l>=dl&&r<=dr){
        if(op==1){
            mx[p]=k;t1[p]=k;
            t2[p]=0;
        }else{
            mx[p]+=k;t2[p]+=k;
        }
        return;
    }int mid=l+r>>1;
    pd(p<<1,t1[p],t2[p]);pd(p<<1|1,t1[p],t2[p]);t1[p]=-1;t2[p]=0;
    if(dl<=mid) up(dl,dr,lson,k,op);
    if(dr>mid) up(dl,dr,rson,k,op);
    pp(p);
}
int qy(int dl,int dr,int l,int r,int p){
    if(l>=dl&&r<=dr) return mx[p];
    int mid=l+r>>1;int ret=-inf;
    pd(p<<1,t1[p],t2[p]);pd(p<<1|1,t1[p],t2[p]);t1[p]=-1;t2[p]=0;
    if(dl<=mid) ret=max(ret,qy(dl,dr,lson));
    if(dr>mid) ret=max(ret,qy(dl,dr,rson));
    return ret;
}
void dfs1(int u){
    sz[u]=1;d[u]=d[f[u]]+1;
    for(pii x:g[u]){
        if(x.fi==f[u]) continue;
        f[x.fi]=u;dfs1(x.fi);
        a[x.fi]=w[x.se];b[x.se]=x.fi;sz[u]+=sz[x.fi];
        if(sz[x.fi]>sz[son[u]]) son[u]=x.fi;
    }
}
void dfs2(int u,int t){
    top[u]=t;p[u]=++tot;id[tot]=u;
    if(son[u]) dfs2(son[u],t);
    for(pii x:g[u]){
        if(x.fi==f[u]||x.fi==son[u]) continue;
        dfs2(x.fi,x.fi);
    }
}
void col(int x,int y,int k,int op){
    while(top[x]!=top[y]){
        if(d[top[x]]<d[top[y]]) swap(x,y);
        up(p[top[x]],p[x],1,n,1,k,op);
        x=f[top[x]];
    }
    if(d[x]<d[y]) swap(x,y);
    up(p[y]+1,p[x],1,n,1,k,op);
}
int cal(int x,int y){
    int res=-inf;
    while(top[x]!=top[y]){
        if(d[top[x]]<d[top[y]]) swap(x,y);
        res=max(res,qy(p[top[x]],p[x],1,n,1));
        x=f[top[x]];
    }
    if(d[x]<d[y]) swap(x,y);
    return max(res,qy(p[y]+1,p[x],1,n,1));
}
int main(){
    scanf("%d",&n);
    for(int i=1,a,b;i<n;i++){
        scanf("%d%d%d",&a,&b,&w[i]);
        g[a].pb(pii(b,i));g[b].pb(pii(a,i));
    }
    dfs1(1);dfs2(1,1);bd(1,n,1);
    char s[20];
    while(~scanf("%s",s)){
        if(s[0]=='S') break;
        int x,u,v,k;
        if(s[0]=='C'&&s[1]=='h'){
            scanf("%d%d",&x,&k);
            int pos=p[b[x]];
            up(pos,pos,1,n,1,k,1);
        }else if(s[0]=='C'&&s[1]=='o'){
            scanf("%d%d%d",&u,&v,&k);
            col(u,v,k,1);
        }else if(s[0]=='A'){
            scanf("%d%d%d",&u,&v,&k);
            col(u,v,k,2);
        }else{
            scanf("%d%d",&u,&v);
            printf("%d\n",cal(u,v));
        }
    }
    return 0;
}
全部评论

相关推荐

把球:这个听过,你加了就会发现是字节的hr
点赞 评论 收藏
分享
感性的干饭人在线蹲牛友:🐮 应该是在嘉定这边叭,禾赛大楼挺好看的
点赞 评论 收藏
分享
评论
点赞
收藏
分享
牛客网
牛客企业服务