BZOJ 3083 遥远的国度(树链剖分+LCA)

Posted Styx-ferryman

tags:

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

Description

描述
zcwwzdjn在追杀十分sb的zhx,而zhx逃入了一个遥远的国度。当zcwwzdjn准备进入遥远的国度继续追杀时,守护神RapiD阻拦了zcwwzdjn的去路,他需要zcwwzdjn完成任务后才能进入遥远的国度继续追杀。

问题是这样的:遥远的国度有n个城市,这些城市之间由一些路连接且这些城市构成了一颗树。这个国度有一个首都,我们可以把这个首都看做整棵树的根,但遥远的国度比较奇怪,首都是随时有可能变为另外一个城市的。遥远的国度的每个城市有一个防御值,有些时候RapiD会使得某两个城市之间的路径上的所有城市的防御值都变为某个值。RapiD想知道在某个时候,如果把首都看做整棵树的根的话,那么以某个城市为根的子树的所有城市的防御值最小是多少。由于RapiD无法解决这个问题,所以他拦住了zcwwzdjn希望他能帮忙。但zcwwzdjn还要追杀sb的zhx,所以这个重大的问题就被转交到了你的手上。

Input

第1行两个整数n m,代表城市个数和操作数。
第2行至第n行,每行两个整数 u v,代表城市u和城市v之间有一条路。
第n+1行,有n个整数,代表所有点的初始防御值。
第n+2行一个整数 id,代表初始的首都为id。
第n+3行至第n+m+2行,首先有一个整数opt,如果opt=1,接下来有一个整数id,代表把首都修改为id;如果opt=2,接下来有三个整数p1 p2 v,代表将p1 p2路径上的所有城市的防御值修改为v;如果opt=3,接下来有一个整数 id,代表询问以城市id为根的子树中的最小防御值。

Output


对于每个opt=3的操作,输出一行代表对应子树的最小点权值。

Sample Input

3 7

1 2

1 3

1 2 3

1

3 1

2 1 1 6

3 1

2 2 2 5

3 1

2 3 3 4

3 1

Sample Output

1

2

3

4

提示

对于20%的数据,n<=1000 m<=1000。

对于另外10%的数据,n<=100000,m<=100000,保证修改为单点修改。

对于另外10%的数据,n<=100000,m<=100000,保证树为一条链。

对于另外10%的数据,n<=100000,m<=100000,没有修改首都的操作。

对于100%的数据,n<=100000,m<=100000,0<所有权值<=2^31。

题解:首先看到路径修改和子树查询,树链剖分就没得跑了,当然也可以写LCT

操作2/3用树剖自然好写,难的是一,换根怎么看怎么尬

想了一想,如果根就是询问点,子树就是整个区间

如果根在祖先,该点的子树不变.仍是按照正规的树剖查法查

如果根在询问点的任何一个子树中,那么该询问点的子树就变成了除了这个子树之外的所有区间.

主要是如何确定这个根在哪个子树中比较麻烦,写一个类似lca的玩意,倍增记录他的祖先,到时候一点点跳上去,复杂度还是可以接受的.

我一直以为是线段树写错了,果然做题太少了orz

代码如下:

#include<cstdio>
#include<vector>
#include<cstring>
#include<iostream>
#include<algorithm>
#define lson root<<1
#define rson root<<1|1
#define inf 0x3f3f3f3f
using namespace std;

struct node
{
    int lazy,m,l,r;
} tr[400040];
int n,deep[100010],son[100010],fa[100010],size[100010],id[100010],top[100010],c[100010],w[100010],cnt,rt;
vector<int> g[100010];

void push_up(int root)
{
    tr[root].m=min(tr[lson].m,tr[rson].m);
}

void push_down(int root)
{
    tr[lson].m=tr[root].lazy;
    tr[lson].lazy=tr[root].lazy;
    tr[rson].m=tr[root].lazy;
    tr[rson].lazy=tr[root].lazy;
    tr[root].lazy=inf;
}

void build(int root,int l,int r)
{
    if(l==r)
    {
        tr[root].l=l;
        tr[root].r=r;
        tr[root].lazy=inf;
        tr[root].m=w[l];
        return ;
    }
    int mid=(l+r)>>1;
    tr[root].l=l;
    tr[root].r=r;
    tr[root].lazy=inf;
    build(lson,l,mid);
    build(rson,mid+1,r);
    push_up(root);
}

void update(int root,int l,int r,int val)
{
    if(l==tr[root].l&&r==tr[root].r)
    {
        tr[root].lazy=val;
        tr[root].m=val;
        return ;
    }
    int mid=(tr[root].l+tr[root].r)>>1;
    if(tr[root].lazy!=inf)
    {
        push_down(root);
    }
    if(l>mid)
    {
        update(rson,l,r,val);
    }
    else
    {
        if(r<=mid)
        {
            update(lson,l,r,val);
        }
        else
        {
            update(lson,l,mid,val);
            update(rson,mid+1,r,val);
        }
    }
    push_up(root);
}

int query(int root,int l,int r)
{
    if(l>r)
    {
        return inf;
    }
    if(tr[root].l==l&&tr[root].r==r)
    {
        return tr[root].m;
    }
    int mid=(tr[root].l+tr[root].r)>>1;
    if(tr[root].lazy!=inf)
    {
        push_down(root);
    }
    if(l>mid)
    {
        return query(rson,l,r);
    }
    else
    {
        if(r<=mid)
        {
            return query(lson,l,r);
        }
    }
    return min(query(lson,l,mid),query(rson,mid+1,r));
}

void dfs1(int now,int f,int dep)
{
    deep[now]=dep;
    fa[now]=f;
    size[now]=1;
    int maxson=-1;
    for(int i=0; i<g[now].size(); i++)
    {
        if(g[now][i]==f)
        {
            continue;
        } 
        dfs1(g[now][i],now,dep+1);
        size[now]+=size[g[now][i]];
        if(size[g[now][i]]>maxson)
        {
            son[now]=g[now][i];
            maxson=size[g[now][i]];
        }
    }
}

void dfs2(int now,int topf)
{
    id[now]=++cnt;
    w[cnt]=c[now];
    top[now]=topf;
    if(!son[now])
    {
        return ;
    }
    dfs2(son[now],topf);
    for(int i=0; i<g[now].size(); i++)
    {
        if(g[now][i]==fa[now]||g[now][i]==son[now])
        {
            continue;
        }
        dfs2(g[now][i],g[now][i]);
    }
}

void path_update(int x,int y,int val)
{
    while(top[x]!=top[y])
    {
        if(deep[top[x]]<deep[top[y]])
        {
            swap(x,y);
        }
        update(1,id[top[x]],id[x],val);
        x=fa[top[x]];
    }
    if(deep[x]>deep[y])
    {
        swap(x,y);
    }
    update(1,id[x],id[y],val);
}

int sub_query(int x)
{
    if(x==rt)
    {
        return query(1,1,cnt);
    }
    if(id[rt]<=id[x]+size[x]-1&&id[rt]>=id[x])
    {
        return min(query(1,1,id[x]-1),query(1,id[x]+size[x],cnt));
    }
    return query(1,id[x],id[x]+size[x]-1);
}

int main()
{
    int n,m;
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n-1;i++)
    {
        int from,to;
        scanf("%d%d",&from,&to);
        g[from].push_back(to);
        g[to].push_back(from);
    }
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&c[i]);
    }
    scanf("%d",&rt);
    dfs1(rt,0,1);
    dfs2(rt,rt);
    build(1,1,n);
    int kd,ll,rr,vv;
    for(int i=1;i<=m;i++)
    {
        scanf("%d",&kd);
        if(kd==1)
        {
            scanf("%d",&vv);
            rt=vv;
        }
        if(kd==2)
        {
            scanf("%d%d%d",&ll,&rr,&vv);
            path_update(ll,rr,vv);
        }
        if(kd==3)
        {
            scanf("%d",&vv);
            printf("%d\n",sub_query(vv));
        }
    }
}

 

以上是关于BZOJ 3083 遥远的国度(树链剖分+LCA)的主要内容,如果未能解决你的问题,请参考以下文章

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

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

bzoj3083: 遥远的国度

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

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

BZOJ3083 遥远的国度