zoukankan      html  css  js  c++  java
  • P4315 月下“毛景树” (树链剖分+边剖分+区间覆盖+区间加+区间最大值)

    题目链接: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
    ",ask(l,r)); //Max操作 
            }
        }
        return 0;
    }
  • 相关阅读:
    Python3小练习2——(汉诺塔的移动),递归
    Python3小练习1——(ax*x+ bx + c = 0的解)
    SSRS数据导出Excel多出空白列
    ETL 压缩文件(makecab) 并邮件发送
    关于System.Web.Script.Serialization命名空间的引用
    如何通过VIsual Studio安装程序修改VS2017?
    如何其他服务器能够连接自己本机的数据库?
    SSAS表格模型部署问题
    表格模型——安装实例
    Leetcode 76题:最小覆盖子串 滑动窗口经典题
  • 原文地址:https://www.cnblogs.com/zjl192628928/p/11301710.html
Copyright © 2011-2022 走看看