ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

P4315 月下“毛景树” (树链剖分+边剖分+区间覆盖+区间加+区间最大值)

2019-08-05 11:01:16  阅读:149  来源: 互联网

标签:rt 剖分 val 毛景树 mid int maxn 区间 id


题目链接:https://www.luogu.org/problem/P4315

题目大意:

有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之间树枝上毛毛果个数最多有多少个。

 

解题思路:一道边权树剖题,代码很长,调试起来还是有点复杂。

注意一下几点:

1.可以把边权转化为点权,因为每一个孩子节点通向父节点的边是唯一的,所以可以将每个边的边权转到边所连的孩子节点上(可在树剖的第一个dfs中完成)

2.修改一条链上的权值时,要注意链两端的点的lca不能够被修改,因为lca所对应的边权不在这一条链上。

3.Change 操作是修改第k条树枝,k为读入的顺序,而树的存边是双向的,所以要将读入的k乘以二在进行后面的操作。

4.下推标记的时候如果有覆盖标记不要忘了清除加的标记

 

代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=100005;
int tot,cnt,head[maxn],n,m,v[maxn];
ll tree[maxn*4],lazy[maxn*4],cov[maxn*4];
int d[maxn],size[maxn],son[maxn],id[maxn],rk[maxn],fa[maxn],top[maxn];
//cov为覆盖标记,lazy为累加标记 
struct Edge{
    int u,v,w,next;
}edge[maxn<<1];
void add(int u,int v,int w){
    edge[++tot].v=v;
    edge[tot].u=u;
    edge[tot].w=w;
    edge[tot].next=head[u];
    head[u]=tot;
}
void dfs1(int u,int pre){
    d[u]=d[pre]+1;
    fa[u]=pre;
    size[u]=1;
    for(int i=head[u];i!=-1;i=edge[i].next){
        int vv=edge[i].v;
        if(vv!=pre){
            dfs1(vv,u);
            size[u]+=size[vv];
            v[vv]=edge[i].w;  //边权转为点权 
            if(size[son[u]]<size[vv]) son[u]=vv;
        }
    }
}
void dfs2(int u,int tp){
    top[u]=tp,id[u]=++cnt,rk[cnt]=u;
    if(son[u]) dfs2(son[u],tp);  
    for(int i=head[u];i!=-1;i=edge[i].next){
        int v=edge[i].v;
        if(v!=fa[u]&&v!=son[u]) dfs2(v,v);
    }
}
void pushup(int rt){
    tree[rt]=max(tree[rt<<1],tree[rt<<1|1]);
}
void pushdown(int l,int r,int rt){
    if(cov[rt]!=-1){
        cov[rt<<1]=cov[rt<<1|1]=cov[rt];
        tree[rt<<1]=tree[rt<<1|1]=cov[rt];
        lazy[rt<<1]=lazy[rt<<1|1]=0; //将孩子节点的lazy标记清0 
        cov[rt]=-1;
    }
    if(lazy[rt]){
        tree[rt<<1]=tree[rt<<1]+lazy[rt];
        tree[rt<<1|1]=tree[rt<<1|1]+lazy[rt];
        lazy[rt<<1]+=lazy[rt];
        lazy[rt<<1|1]+=lazy[rt];
        lazy[rt]=0;
    }
}
void build(int l,int r,int rt){
    lazy[rt]=0;
    cov[rt]=-1;
    if(l==r){
        tree[rt]=v[rk[l]];
        return;
    }
    int mid=l+r>>1;
    build(l,mid,rt<<1);
    build(mid+1,r,rt<<1|1);
    pushup(rt);
}
void update1(int L,int R,int val,int l,int r,int rt){ //区间Cover和Change 
    if(L<=l&&R>=r){
        tree[rt]=val;
        cov[rt]=val;
        lazy[rt]=0; //将lazy标记清0 
        return;
    }
    int mid=l+r>>1;
    pushdown(mid-l+1,r-mid,rt);
    if(mid>=L) update1(L,R,val,l,mid,rt<<1);
    if(mid<R) update1(L,R,val,mid+1,r,rt<<1|1);
    pushup(rt);
}
void update2(int L,int R,int val,int l,int r,int rt){ //区间Add 
    if(L<=l&&R>=r){
        tree[rt]+=val;
        lazy[rt]+=val;
        return;
    }
    int mid=l+r>>1;
    pushdown(mid-l+1,r-mid,rt);
    if(mid>=L) update2(L,R,val,l,mid,rt<<1);
    if(mid<R) update2(L,R,val,mid+1,r,rt<<1|1);
    pushup(rt);
}
ll query(int L,int R,int l,int r,int rt){ //区间求Max 
    if(L<=l&&R>=r) return tree[rt];
    int mid=l+r>>1; ll res=0;
    pushdown(mid-l+1,r-mid,rt);
    if(mid>=L) res=max(res,query(L,R,l,mid,rt<<1));
    if(mid<R) res=max(res,query(L,R,mid+1,r,rt<<1|1));
    return res;
}
void updates1(int x,int y,int val){ //Cover 
    while(top[x]!=top[y]){ 
        if(d[top[x]]<d[top[y]]) swap(x,y);
        update1(id[top[x]],id[x],val,1,n,1); 
        x=fa[top[x]];
    }
    if(id[x]>id[y]) swap(x,y);
    update1(id[x]+1,id[y],val,1,n,1); //不能更新lca所以是id[x]+1 
}
void updates2(int x,int y,int val){ //Add 
    while(top[x]!=top[y]){ 
        if(d[top[x]]<d[top[y]]) swap(x,y);
        update2(id[top[x]],id[x],val,1,n,1); 
        x=fa[top[x]];
    }
    if(id[x]>id[y]) swap(x,y);
    update2(id[x]+1,id[y],val,1,n,1); //不能更新lca所以是id[x]+1 
}
ll ask(int x,int y){ //求Max 
    ll res=0;
    while(top[x]!=top[y]){
        if(d[top[x]]<d[top[y]]) swap(x,y);
        res=max(res,query(id[top[x]],id[x],1,n,1));
        x=fa[top[x]];
    }
    if(id[x]>id[y]) swap(x,y);
    res=max(res,query(id[x]+1,id[y],1,n,1));
    return res;
}
int main(){
    scanf("%d",&n);
    memset(head,-1,sizeof(head));
    cnt=0,tot=0;
    for(int i=1;i<n;i++){
        int u,v,w;
        scanf("%d%d%d",&u,&v,&w);
        add(u,v,w); add(v,u,w);
    }
    dfs1(1,0),dfs2(1,1);
    build(1,n,1);
    while(true){
        char op[10];
        int x,l,r,rt,val;
        scanf("%s",op);
        if(op[1]=='t') break;
        if(op[1]=='h'){
            scanf("%d%d",&x,&val); //因为是无向边,所以x*2表示的就是第x条边 
            x=d[edge[x*2].u]>d[edge[x*2].v]?edge[x*2].u:edge[x*2].v;
            update1(id[x],id[x],val,1,n,1);  //Change操作 
        } else if(op[1]=='o'){
            scanf("%d%d%d",&l,&r,&val);
            updates1(l,r,val); //Cover操作 
        } else if(op[1]=='d'){
            scanf("%d%d%d",&l,&r,&val);
            updates2(l,r,val); //Add操作 
        } else if(op[1]=='a'){
            scanf("%d%d",&l,&r);
            printf("%lld\n",ask(l,r)); //Max操作 
        }
    }
    return 0;
}

 

标签:rt,剖分,val,毛景树,mid,int,maxn,区间,id
来源: https://www.cnblogs.com/zjl192628928/p/11301710.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有