zoukankan      html  css  js  c++  java
  • 月下“毛景树” 树链剖分模板题(洛谷P4315)

    树链剖分维护的都是点,而这道题要求的是边。

    解决:就把边权下放,变成点权,注意下放后查询u到v的路径时要除去lca的点权,因为lca的点权是其父亲的边权

    细节:线段树的加标记与等于标记的维护与下传

    #include<bits/stdc++.h>
    using namespace std;
    #define N 100005
    #define mid ((l+r)>>1)
    int mx[N*4],fl[N*4],eq[N*4],n;
    int head[N],to[N<<1],nex[N<<1],w[N<<1],tot=0;
    int cnt=0,id[N],dfn[N],val[N],siz[N],dep[N],fa[N],son[N],top[N];
    struct node{ int a,b; } e[N<<1];
    void add(int a,int b,int c) { to[++tot]=b; nex[tot]=head[a]; head[a]=tot; w[tot]=c; }
    void update(int s) { mx[s]=max(mx[s<<1],mx[s<<1|1]); }
    void pushdown(int s)//优先处理=标记 
    {
        if(eq[s]!=-1){
            fl[s<<1]=fl[s<<1|1]=0;
            mx[s<<1]=mx[s<<1|1]=eq[s<<1]=eq[s<<1|1]=eq[s];
            eq[s]=-1;
        }
        else if(fl[s]){
            fl[s<<1]+=fl[s]; 
            fl[s<<1|1]+=fl[s]; 
            mx[s<<1]+=fl[s];
            mx[s<<1|1]+=fl[s];
            fl[s]=0;
        }
    }
    void build(int s,int l,int r)
    {
        fl[s]=0; eq[s]=-1;
        if(l==r) { mx[s]=dfn[l]; return ; }
        build(s<<1,l,mid); build(s<<1|1,mid+1,r);
        update(s);
    }
    void modify_point(int s,int l,int r,int pos,int v)
    {
        if(l==r) { mx[s]=v; fl[s]=0; eq[s]=v; return ; }//eq=v??
        pushdown(s);
        if(pos<=mid) modify_point(s<<1,l,mid,pos,v); 
        else modify_point(s<<1|1,mid+1,r,pos,v);
        update(s);
    }
    void modify_add(int s,int l,int r,int L,int R,int v)
    {
        if(L<=l&&r<=R) { mx[s]+=v; fl[s]+=v; return ; }
        pushdown(s);
        if(L<=mid) modify_add(s<<1,l,mid,L,R,v);
        if(R>mid)  modify_add(s<<1|1,mid+1,r,L,R,v);
        update(s);
    }
    void modify_cover(int s,int l,int r,int L,int R,int v)
    {
        //printf("%d %d
    ",l,r);
        if(L<=l&&r<=R) { mx[s]=eq[s]=v; fl[s]=0; return ; }
        pushdown(s);
        if(L<=mid) modify_cover(s<<1,l,mid,L,R,v);
        if(R>mid)  modify_cover(s<<1|1,mid+1,r,L,R,v);
        update(s);
    }
    int query(int s,int l,int r,int L,int R)
    {
        int ans=0;
        if(L<=l&&r<=R) return mx[s];
        pushdown(s);
        if(L<=mid) ans=max(ans,query(s<<1,l,mid,L,R));
        if(R>mid)  ans=max(ans,query(s<<1|1,mid+1,r,L,R));
        return ans;
    }
    void dfs1(int u,int f)
    {
        siz[u]=1;
        for(int i=head[u];i;i=nex[i]){
            int v=to[i];
            if(v==f) continue;
            fa[v]=u; dep[v]=dep[u]+1; val[v]=w[i];
            dfs1(v,u);
            siz[u]+=siz[v];
            if(siz[son[u]]<siz[v]) son[u]=v;
        }
    }
    void dfs2(int u,int tp)
    {
        id[u]=++cnt;
        dfn[cnt]=val[u];
        top[u]=tp;
        if(son[u]) dfs2(son[u],tp);
        for(int i=head[u];i;i=nex[i]){
            int v=to[i];
            if(v==fa[u]||v==son[u]) continue;
            dfs2(v,v);
        }
    }
    void modify1(int i,int ww)
    {
        if(fa[e[i].a]==e[i].b) modify_point(1,1,n,id[e[i].a],ww);
        else modify_point(1,1,n,id[e[i].b],ww);
    }
    void modify2(int a,int b,int ww,bool op)
    {
        while(top[a]!=top[b]){
            if(dep[top[a]]<dep[top[b]]) swap(a,b);
            if(op)
            modify_add(1,1,n,id[top[a]],id[a],ww);
    
            else modify_cover(1,1,n,id[top[a]],id[a],ww);
            a=fa[top[a]]; 
        }
        if(dep[a]<dep[b]) swap(a,b);
        if(op) modify_add(1,1,n,id[b]+1,id[a],ww);//+1是为了保证没有算到lca那一条边!! id[b]+1 
        else modify_cover(1,1,n,id[b]+1,id[a],ww);//要记得+1!! 
    }
    int query_link(int a,int b)
    {
        int ans=0;
        while(top[a]!=top[b]){
            if(dep[top[a]]<dep[top[b]]) swap(a,b);
            ans=max(ans,query(1,1,n,id[top[a]],id[a]));
            a=fa[top[a]];
        }
        if(dep[a]<dep[b]) swap(a,b);
        ans=max(ans,query(1,1,n,id[b]+1,id[a]));//
        return ans;
    }
    char op[10];
    int main()
    {
        int a,b,c,x;
        scanf("%d",&n);
        for(int i=1;i<=n-1;++i) 
         scanf("%d%d%d",&e[i].a,&e[i].b,&c),add(e[i].a,e[i].b,c),add(e[i].b,e[i].a,c);
        dfs1(1,0); dfs2(1,1); build(1,1,n);
        while(1){
            scanf("%s",op);
            if(op[0]=='S') break;
            scanf("%d%d",&a,&b);
            if(op[0]=='C'&&op[1]=='h') modify1(a,b);
            else if(op[0]=='C') scanf("%d",&x),modify2(a,b,x,0);
            else if(op[0]=='A') scanf("%d",&x),modify2(a,b,x,1);
            else printf("%d
    ",query_link(a,b));
        }
    }
    /*
    10
    1 6 0
    2 10 8
    3 5 8
    4 9 1
    5 8 3
    6 7 1
    7 5 0
    9 2 8
    10 6 0
    Cover 5 9 1
    Max 7 10
    Add 4 2 5
    Change 2 6
    Add 9 2 8
    Change 3 6
    Max 1 6  
    Cover 2 7 3
    Max 7 9
    Cover 5 8 5
    Stop
    ans 1 0 14
    */
    View Code
  • 相关阅读:
    Django错误笔记1
    Django学习笔记1 启动及配置一个Django项目
    ubuntu 安装mysqldb
    二叉树 总结
    序列二叉树和反序列 (不是自己做的)
    二叉树的路径
    二叉搜索树的后续遍历
    二叉树层序遍历
    栈的压入 弹出序列
    包含 min的栈
  • 原文地址:https://www.cnblogs.com/mowanying/p/11247221.html
Copyright © 2011-2022 走看看