zoukankan      html  css  js  c++  java
  • 题解 [CF916E] Jamie and Tree

    题面

    解析

    这题考试时刚了四个小时.

    结果还是爆零了

    主要就是因为(lca)找伪了.

    我们先考虑没有操作1,那就是裸的线段树.

    在换了根以后,主要就是(lca)不好找(分类讨论伪了).

    我们将一开始以(1)为根的图作为原图.

    仔细思考一下,

    我们会发现只有当原图上的(lca)(1)和当前的根的路径上时,(lca)才会发生变化.

    考试时怎么没发现

    而当(lca)变化后,我们画一下图,

    就会发现,

    现在的(lca)就是两个点与根的(lca)中深度较大的一个.

    (这个(yy)一下就能明白了)

    然后,我们再考虑修改查询.(实际上它们的道理是一样的)

    假设我们要修改查询的是(p)的子树,

    如果根不在(p)的子树里,就直接来就行了,

    否则,从根到(p)的路径上的所有分出去的点就不会被修改(画下图就能明白),

    所以我们直接全图加一下,

    设根在(p)的儿子(k)的子树里,

    那么将(k)的子树全部减一下就行了.

    至于找(k),可以用倍增,

    修改查询可以用线段树&树链剖分.

    code:

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #define int long long
    #define ls(a) a<<1
    #define rs(a) a<<1|1
    #define fre(x) freopen(x".in","r",stdin),freopen(x".out","w",stdout)
    using namespace std;
    
    inline int read(){
        int sum=0,f=1;char ch=getchar();
        while(ch>'9' || ch<'0'){if(ch=='-')f=-1;ch=getchar();}
        while(ch>='0' && ch<='9'){sum=sum*10+ch-'0';ch=getchar();}
        return f*sum;
    }
    
    const int N=600001;
    struct tree{int l,r,sum,tag;}t[N<<1];
    struct node{int val,fa,size,son,dep,id,top;}a[N];
    struct edge{int to,next;}e[N<<1];
    int n,m,rt=1;
    int head[N],cnt=0;
    int tot,pla[N],f[N][21];
    
    inline void add(int x,int y){
        e[++cnt]=(edge){head[x],y};head[x]=cnt;
    }
    
    void dfs1(int x,int fa){
        a[x].size=1;a[x].fa=fa;a[x].dep=a[fa].dep+1;
        f[x][0]=fa;
        for(int i=1;i<=20;i++) f[x][i]=f[f[x][i-1]][i-1];
        for(int i=head[x];i;i=e[i].to){
            int k=e[i].next;if(k==fa) continue;
            dfs1(k,x);a[x].size+=a[k].size;
            if(!a[x].son||a[k].size>a[a[x].son].size) a[x].son=k;
        }
    }
    
    void dfs2(int x,int top){
        a[x].top=top;a[x].id=++tot;pla[tot]=x;
        if(a[x].son) dfs2(a[x].son,top);
        for(int i=head[x];i;i=e[i].to){
            int k=e[i].next;if(k==a[x].fa||k==a[x].son) continue;
            dfs2(k,k);
        }
    }
    
    inline int lca(int x,int y){
        while(a[x].top!=a[y].top){
            if(a[a[x].top].dep<a[a[y].top].dep) swap(x,y);
            x=a[a[x].top].fa;
        }
        if(a[x].dep>a[y].dep) swap(x,y);
        return x;
    }
    
    inline void pushup(int p){
        t[p].sum=t[ls(p)].sum+t[rs(p)].sum;
    }
    
    inline void pushdown(int p){
        if(!t[p].tag) return ;
        int l=ls(p),r=rs(p);
        t[l].tag+=t[p].tag;t[r].tag+=t[p].tag;
        t[l].sum+=(t[l].r-t[l].l+1)*t[p].tag;
        t[r].sum+=(t[r].r-t[r].l+1)*t[p].tag;
        t[p].tag=0;
    }
    
    inline void sg_build(int p,int l,int r){
        t[p].l=l;t[p].r=r;
        if(l==r){t[p].sum=a[pla[l]].val;return ;}
        int mid=(l+r)>>1;
        sg_build(ls(p),l,mid);sg_build(rs(p),mid+1,r);
        pushup(p);
    }
    
    inline void sg_change(int p,int l,int r,int w){
        if(t[p].l>=l&&t[p].r<=r){
            t[p].sum+=(t[p].r-t[p].l+1)*w;t[p].tag+=w;
            return ;
        }
        pushdown(p);
        int mid=(t[p].l+t[p].r)>>1;
        if(l<=mid) sg_change(ls(p),l,r,w);
        if(r>mid) sg_change(rs(p),l,r,w);
        pushup(p);
    }
    
    inline int sg_query(int p,int l,int r){
        if(t[p].l>=l&&t[p].r<=r) return t[p].sum;
        pushdown(p);
        int mid=(t[p].l+t[p].r)>>1,ret=0;
        if(l<=mid) ret+=sg_query(ls(p),l,r);
        if(r>mid) ret+=sg_query(rs(p),l,r);
        pushup(p);
        return ret;
    }
    
    inline int isson(int x,int fa){return a[x].id>=a[fa].id&&a[x].id<=a[fa].id+a[fa].size-1;}
    
    inline void change(int x,int y,int w){
        int p=lca(x,y);
        int f1=lca(p,rt);
        if(f1==p){
            f1=lca(x,rt);int f2=lca(y,rt);
            if(a[f1].dep>a[f2].dep) p=f1;
            else p=f2;
        }
        if(!isson(rt,p)) sg_change(1,a[p].id,a[p].id+a[p].size-1,w);
        else{
            sg_change(1,1,n,w);int k=rt;
            if(isson(k,p)&&rt!=p){
                for(int i=20;i>=0;i--)
                    if(a[f[k][i]].dep>a[p].dep) k=f[k][i];
                sg_change(1,a[k].id,a[k].id+a[k].size-1,-w);
            }
        }
    }
    
    inline void ask(int p){
        int ret=0;
        if(a[rt].id>a[p].id+a[p].size-1||a[rt].id<a[p].id) ret=sg_query(1,a[p].id,a[p].id+a[p].size-1);
        else{
            ret+=sg_query(1,1,n);int k=rt;
            if(isson(k,p)&&rt!=p){
                for(int i=20;i>=0;i--)
                    if(a[f[k][i]].dep>a[p].dep) k=f[k][i];
                ret-=sg_query(1,a[k].id,a[k].id+a[k].size-1);
            }
        }
        printf("%lld
    ",ret);
    }
    
    signed main(){
        n=read();m=read();
        for(int i=1;i<=n;i++) a[i].val=read();
        for(int i=1;i<n;i++){int x=read(),y=read();add(x,y);add(y,x);}
        dfs1(1,0);dfs2(1,1);sg_build(1,1,n);
        for(int i=1;i<=m;i++){
            int opt=read(),x=read();
            if(opt==1) rt=x;
            else if(opt==2) {int y=read(),w=read();change(x,y,w);}
            else if(opt==3) ask(x);
        }
        return 0;
    }
    /*
    6 7
    1 4 2 8 5 7
    1 2
    3 1
    4 3
    4 5
    3 6
    3 1
    2 4 6 3
    3 4
    1 6
    2 2 4 -5
    1 4
    3 3
     */
    
    
  • 相关阅读:
    PHP常用代码大全(新手入门必备)
    一代大商孟洛川的经商之道
    Photoshop调出田园照片唯美手绘油画效果
    Photoshop调出外景婚片蓝色小清新艺术效果
    photoshop快速把新照片制作成老照片教学
    Photoshop调出清晰的阴雨天气山水风景照
    PS调出清新风格社区街拍照片
    PS调出韩式米黄色室内婚纱照片
    PS调出唯美紫蓝色天空背景女生照片
    PS快速调出天蓝色清新外景
  • 原文地址:https://www.cnblogs.com/zsq259/p/11186202.html
Copyright © 2011-2022 走看看