[日常摸鱼]bzoj3083遥远的国度-树链剖分

Posted yoooshinow

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[日常摸鱼]bzoj3083遥远的国度-树链剖分相关的知识,希望对你有一定的参考价值。

一无聊就找树剖写

题意:一颗带点权的树,三种操作:1.换根 2.链赋值 3.查询子树最小值

 


 

 

如果没有换根的话直接就是裸的树剖了,对于换根的操作我们可以分类讨论。

1.如果查询的$x$就是根,那答案就是整棵树的最小值。

2.如果以1为根的dfs序中,根在$x$的子树之外,那很明显$x$的子树还是原来的子树。

3.如果以1为根的dfs序中,根在$x$的子树里面的话,画个图就能发现,找到$x$的孩子中作为根的父亲那个点,答案就是整棵树把整个点的子树去掉就行了。

其他地方跟树剖没什么区别…

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long lint;
const int N=100005;
const lint INF=(1ll<<32);
inline lint read()
{
    lint s=0,f=1;char c=getchar();
    while(c<0||c>9){if(c==-)f=-1;c=getchar();}
    while(c>=0&&c<=9){s=s*10+c-0;c=getchar();}
    return s*f;
}
struct edge
{
    int to,nxt;
}edges[N<<1];
int n,m,cnt,rot,tot;
int head[N<<1],son[N],size[N],dep[N],top[N],dl[N],dr[N],rk[N],fa[N];
lint tr[N<<2],tag[N<<2],v[N];

#define lson (o<<1)
#define rson (o<<1|1)
inline void push_up(int o)
{
    tr[o]=min(tr[lson],tr[rson]);
}
inline void push_down(int o)
{
    if(tag[o]==-1)return;
    tag[lson]=tag[rson]=tag[o];
    tr[lson]=tr[rson]=tag[o];
    tag[o]=-1;
}
inline void build(int o,int l,int r)
{
    tag[o]=-1;
    if(l==r)
    {
        tr[o]=v[rk[l]];
        return;
    }int mid=(l+r)>>1;
    build(lson,l,mid);build(rson,mid+1,r);
    push_up(o);
}
inline void modify(int o,int l,int r,int ql,int qr,lint val)
{
    if(ql<=l&&r<=qr)
    {
        tag[o]=tr[o]=val;
        return;
    }push_down(o);
    int mid=(l+r)>>1;
    if(mid>=ql)modify(lson,l,mid,ql,qr,val);
    if(mid+1<=qr)modify(rson,mid+1,r,ql,qr,val);
    push_up(o);
}
inline lint query(int o,int l,int r,int ql,int qr)
{
    if(ql<=l&&r<=qr)return tr[o];
    push_down(o);
    int mid=(l+r)>>1;lint res=INF;
    if(mid>=ql)res=min(res,query(lson,l,mid,ql,qr));
    if(mid+1<=qr)res=min(res,query(rson,mid+1,r,ql,qr));
    return res;
}

#undef lson
#undef rson 
inline void addEdge(int u,int v)
{
    edges[++cnt]=(edge){v,head[u]};
    head[u]=cnt;
}
#define cur edges[i].to
inline void dfs1(int x)
{
    size[x]=1;
    for(register int i=head[x];i;i=edges[i].nxt)
        if(cur!=fa[x])
        {
            fa[cur]=x;dep[cur]=dep[x]+1;
            dfs1(cur);size[x]+=size[cur];
            if(size[son[x]]<size[cur])son[x]=cur; 
        }
}
inline void dfs2(int x,int t)
{
    top[x]=t;dl[x]=++tot;rk[tot]=x;
    if(son[x])dfs2(son[x],t);
    for(register int i=head[x];i;i=edges[i].nxt)
        if(cur!=fa[x]&&cur!=son[x])dfs2(cur,cur);
    dr[x]=tot;
}
#undef cur
inline void modify_link(int a,int b,int val)
{
    while(top[a]!=top[b])
    {
        if(dep[top[a]]<dep[top[b]])swap(a,b);
        modify(1,1,n,dl[top[a]],dl[a],val);
        a=fa[top[a]];
    }
    if(dep[a]>dep[b])swap(a,b);
    modify(1,1,n,dl[a],dl[b],val);
}
inline lint query_tree(int x)
{
    if(rot==x)return query(1,1,n,1,n);
    if(dl[x]<=dl[rot]&&dl[rot]<=dr[x])
    {
        int y;
        for(register int i=head[x];i;i=edges[i].nxt)
            if(dl[edges[i].to]<=dl[rot]&&dl[rot]<=dr[edges[i].to])
            {
                y=edges[i].to;
                break;
            }
        return min(query(1,1,n,1,dl[y]-1),query(1,1,n,dr[y]+1,n));
    }else
    {
        return query(1,1,n,dl[x],dr[x]);
    }
}
int main()
{
    n=read();m=read();rot=1;
    for(register int i=1;i<n;i++)
    {
        int u,v;u=read();v=read();
        addEdge(u,v);addEdge(v,u);
    }
    for(register int i=1;i<=n;i++)v[i]=read();
    rot=read();
    dfs1(1);dfs2(1,1);build(1,1,n);
    for(register int i=1;i<=m;i++)
    {
        int op,x,y,val;op=read();
        if(op==1)
        {
            rot=read();
        }else if(op==2)
        {
            x=read();y=read();val=read();
            modify_link(x,y,val);
        }else
        {
            x=read();
            printf("%lld\n",query_tree(x));
        }
    }
}

 

以上是关于[日常摸鱼]bzoj3083遥远的国度-树链剖分的主要内容,如果未能解决你的问题,请参考以下文章

bzoj3083遥远的国度(树链剖分+线段树)

BZOJ 3083 遥远的国度 树链剖分+线段树

bzoj3083: 遥远的国度

遥远的国度(树链剖分,换根)

洛谷 P3979 遥远的国度(树链剖分)

BZOJ 3083 遥远的国度