CF916E Jamie and Tree

CF916E Jamie and Tree

分析

换根树剖

这类题目不多,一般都是需要分类讨论。

题意:

支持以下操作:

  1. 换根
  2. 子树修改
  3. LCA
  4. 子树查询

我们挨个分析

先以1为根将整棵树剖一遍

接着处理每个操作:

1.直接换

2.我们要分类讨论,为了叙述方便,记x,y在原树中的LCAlca(x,y)

对于任意一点x,有以下几种情况:

(1)x=root,修改整棵树

(2)lca(x,root)!=x,那么换根不影响子树,直接修改

(3)lca(x,root)=x,则我们直接找到从root到x的路径中,x的直接儿子,将直接儿子的子树除去,其余部分都是x的子树。

3.我们依然要分类讨论:

我们不妨默认\(dep[x]\leq dep[y]\)

进行分类讨论:

(1)lca(x,y)=x

1)rooty的子树中,那么答案为y

img

2)rootxy之间,那么答案为root

img

3)root在其他位置,那么答案为x

img

(2)lca(x,y)!=x

1)rootx的子树中,那么答案为x

img

2)rooty的子树中,那么答案为y

img

3)rootxy的路径上,那么答案为root

img

4)若lca(x,root)=lca(y,root),即root在下图所示位置,答案为lca(x,y)

img

5)若lca(x,y)!=lca(x,root),即root在下图位置,答案为lca(x,root)

img

6)若lca(x,y)!=lca(y,root),即root在下图位置,答案为lca(y,root)

img

4.同2,进行分类讨论查询

Ac_code

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 1e5 + 10,M = N*2;
const LL INF = 1e18;
struct Node
{
    int l,r;    
    LL sum,tag;//可能加负数
}tr[N<<2];
int h[N],e[M],ne[M],w[N],idx;
int sz[N],son[N],fa[N],dep[N];
int top[N],id[N],nw[N],ts;
int n,q,root;

void add(int a,int b)
{
    e[idx] = b,ne[idx] = h[a],h[a] = idx++;
}

void dfs1(int u,int pa,int depth)
{
    sz[u] = 1,dep[u] = depth;
    for(int i=h[u];~i;i=ne[i])
    {
        int j = e[i];
        if(j==pa) continue;
        fa[j] = u;
        dfs1(j,u,depth+1);
        sz[u] += sz[j];
        if(sz[j]>sz[son[u]]) son[u] = j;
    }
}

void dfs2(int u,int tp)
{
    top[u] = tp,id[u] = ++ts,nw[ts] = w[u];
    if(!son[u]) return ;
    dfs2(son[u],tp);
    for(int i=h[u];~i;i=ne[i])
    {
        int j = e[i];
        if(j==son[u]||j==fa[u]) continue;
        dfs2(j,j);
    }
}

void pushup(int u)
{
    tr[u].sum = tr[u<<1].sum + tr[u<<1|1].sum;
}

void build(int u,int l,int r)
{
    if(l==r)
    {
        tr[u] = {l,r,nw[l],0};
        return ;
    }
    tr[u] = {l,r};
    int mid = l + r >> 1;
    build(u<<1,l,mid),build(u<<1|1,mid+1,r);
    pushup(u);
}

void pushdown(int u)
{
    auto &root = tr[u],&left = tr[u<<1],&right = tr[u<<1|1];
    if(root.tag)
    {
        left.tag += root.tag;
        left.sum += root.tag*(left.r - left.l + 1);
        right.tag += root.tag;
        right.sum += root.tag*(right.r - right.l + 1);
        root.tag = 0;
    }
}

void modify(int u,int l,int r,int k)
{
    if(l<=tr[u].l&&tr[u].r<=r) 
    {
        tr[u].tag += k;
        tr[u].sum += 1ll*k*(tr[u].r - tr[u].l + 1);
        return ;
    }
    pushdown(u);
    int mid = tr[u].l + tr[u].r >> 1;
    if(l<=mid) modify(u<<1,l,r,k);
    if(r>mid) modify(u<<1|1,l,r,k);
    pushup(u);
}

LL query(int u,int l,int r)
{
    if(l<=tr[u].l&&tr[u].r<=r) return tr[u].sum;
    pushdown(u);
    int mid = tr[u].l + tr[u].r >> 1;
    LL res = 0;
    if(l<=mid) res += query(u<<1,l,r);
    if(r>mid) res += query(u<<1|1,l,r);
    return res;
}

int lca(int x,int y)
{
    while(top[x]!=top[y]) 
    {
        if(dep[top[x]]<dep[top[y]]) swap(x,y);
        x = fa[top[x]];
    }
    return dep[x]<dep[y]?x:y;
}

int find(int x)
{
    int u = root;
    while(top[u]!=top[x])
    {
        if(fa[top[u]]==x) return top[u];
        u = fa[top[u]];
    }
    return son[x];
}

int LCA(int x,int y)
{
    if(dep[x]>dep[y]) swap(x,y);
    if(lca(x,y)==x)
    {
        if(id[root]>=id[y]&&id[root]<=id[y]+sz[y]-1) return y;
        if(lca(x,root)==x) return lca(y,root);
        return x;
    }
    if(id[root]>=id[x]&&id[root]<=id[x]+sz[x]-1) return x;
    if(id[root]>=id[y]&&id[root]<=id[y]+sz[y]-1) return y;
    if((lca(x,root)==root&&lca(x,y)==lca(y,root))||(lca(y,root)==root&&lca(x,y)==lca(x,root))) return root;
    if(lca(root,x)==lca(y,root)) return lca(x,y);
    if(lca(x,y)!=lca(x,root)) return lca(x,root);
    return lca(y,root);
}

void mo2(int x,int p)
{
    if(root==x) 
    {
        modify(1,1,n,p);
        return ;
    }
    int res = lca(root,x);
    if(res!=x) modify(1,id[x],id[x]+sz[x]-1,p);
    else 
    {
        int u = find(x);
        modify(1,1,n,p);
        modify(1,id[u],id[u]+sz[u]-1,-p);
    }
}

LL q2(int x)
{
    if(x==root) return query(1,1,n);
    int res = lca(root,x);
    if(res!=x) return query(1,id[x],id[x]+sz[x]-1);
    int u = find(x);
    return query(1,1,n) - query(1,id[u],id[u]+sz[u]-1);
}

int main()
{
    scanf("%d%d",&n,&q);
    memset(h,-1,sizeof h);
    for(int i=1;i<=n;i++) scanf("%d",w+i);
    for(int i=0;i<n-1;i++)
    {
        int u,v;scanf("%d%d",&u,&v);
        add(u,v),add(v,u);
    }
    root = 1;
    dfs1(1,-1,1);
    dfs2(1,1);
    build(1,1,n);
    while(q--)
    {
        int op,x,y,c;
        scanf("%d%d",&op,&x);
        if(op==1) root = x;
        else if(op==2)
        {
            scanf("%d%d",&y,&c);
            mo2(LCA(x,y),c);
        }
        else printf("%lld\n",q2(x));
    }
    return 0;
}

本博客思路,主要来自

绝顶我为峰大佬

posted @ 2022-04-30 22:08  艾特玖  阅读(26)  评论(0编辑  收藏  举报