P397遥远的国度(树剖换根)

P3979 遥远的国度

分析

树剖+线段树+分类讨论(树剖换根)

我们先在这里放结论

  • 换根,不影响我们用从1建立的树剖跑树中路径的操作。
  • 换根,会影响利用子树的性质,因为换过根后,树中结点子树的节点dfs序可能就不连续了,但可以通过分类讨论避免掉,具体看下文。

我们来以本题作为范本讲讲树剖换根

总共三个操作,我们需要关注的仅仅只有第三个操作。

因为根会换,因此,对于同一个节点,当根不同时,其子树也不一定相同。显然,每换一次根就跑一次树剖是不理智的。

那就到了我们需要讲述的关键了,我们可以进行分类讨论

注意:我们这里只根据一号点进行了树剖,root是题目中的首都,在我们的树剖中,我们用的是一号点作为根

  1. 需要查询的点u即为root,则直接查询整棵树即可
  2. 需要查询的点u不在1->root的路径中,那就直接查询该节点下的子树即可
  3. 也是重头戏,需要查询的点u1=>root的路径中,我们只需要删掉从u->root的路径中u的直接儿子v的子树这一部分。而这一部分是连续的,我们只需要查这一部分的两边的连续区间即可得到答案。

主要就是第3种,也很好想

找到路径u->root上的u的直系儿子v

就会发现root为根时,u子树覆盖不到的地方是v及v的子树

下边说一下,怎么找到直系儿子v

就跟树剖找LCA相同,只是最后的时候需要特判一下。

若是最后的时候,我们从一条链翻上去的时候,直接就到了u,那直接返回该条链的头即可

若是已经翻到了同一条链,则直接返回son[u]即可。

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

下边直接看代码

Ac_code

#include<bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10,INF = INT_MAX;
struct Node
{
    int l,r,mi,tag;
}tr[N<<2];
int h[N],e[N<<1],ne[N<<1],w[N],idx;
int sz[N],fa[N],son[N],dep[N];
int top[N],id[N],nw[N],ts;
int n,m,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,fa[u] = pa,dep[u] = depth;
    for(int i=h[u];~i;i=ne[i])
    {
        int j = e[i];
        if(j==pa) continue;
        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==fa[u]||j==son[u]) continue;
        dfs2(j,j);
    }
}

void pushup(int u)
{
    tr[u].mi = min(tr[u<<1].mi,tr[u<<1|1].mi);
}

void pushdown(int u)
{
    auto &root = tr[u],&left = tr[u<<1],&right = tr[u<<1|1];
    if(root.tag)
    {
        left.mi = right.mi = left.tag = right.tag = root.tag;
        root.tag = 0;
    }
}

void build(int u,int l,int r)
{
    if(l==r)
    {
        tr[u] = {l,r,nw[l]};
        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 modify(int u,int l,int r,int x)
{
    if(l<=tr[u].l&&tr[u].r<=r) 
    {
        tr[u].mi = tr[u].tag = x;
        return ;
    }
    pushdown(u);
    int mid = tr[u].l + tr[u].r >> 1;
    if(l<=mid) modify(u<<1,l,r,x);
    if(r>mid) modify(u<<1|1,l,r,x);
    pushup(u);
}

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

int find(int x)
{
    if(x==root) return 1;
    if(id[x]>=id[root]||id[x]+sz[x]-1<id[root]) return 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 main()
{
    scanf("%d%d",&n,&m);
    memset(h,-1,sizeof h);
    for(int i=0;i<n-1;i++) 
    {
        int u,v;scanf("%d%d",&u,&v);
        add(u,v),add(v,u);
    }
    for(int i=1;i<=n;i++) scanf("%d",w+i);
    scanf("%d",&root);
    dfs1(1,-1,1);
    dfs2(1,1);
    build(1,1,n);
    while(m--)
    {
        int op,x,y,z;
        scanf("%d%d",&op,&x);
        if(op==1) root = x;
        else if(op==2)
        {
            scanf("%d%d",&y,&z);
            while(top[x]!=top[y])
            {
                if(dep[top[x]]<dep[top[y]]) swap(x,y);
                modify(1,id[top[x]],id[x],z);
                x = fa[top[x]];
            }
            if(dep[x]<dep[y]) swap(x,y);
            modify(1,id[y],id[x],z);
        }
        else 
        {
            int u = find(x);
            if(u==1) printf("%d\n",query(1,1,n));
            else if(u==x) printf("%d\n",query(1,id[u],id[u]+sz[u]-1));
            else 
            {
                int res = query(1,1,id[u]-1);
                if(id[u]+sz[u]<=n) res = min(res,query(1,id[u]+sz[u],n));
                printf("%d\n",res);
            }
        }
    }
    return 0;
}
posted @ 2022-04-15 17:41  艾特玖  阅读(101)  评论(0)    收藏  举报