博客园 首页 私信博主 显示目录 隐藏目录 管理 动画

题解 [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\n",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
 */

posted @ 2019-07-14 22:31  Hastin  阅读(102)  评论(0编辑  收藏  举报