BZOJ3083: 遥远的国度

BZOJ3083: 遥远的国度

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。

题解Here!
三种操作:换根,区间修改,子树最小值。
如果没有换根,这就是一道树剖的沙茶题。
但是有换根呢?
我们仍然以$1$为根建树。
然后我们分类讨论一下:
1. 如果$now==root$ ,那就是查询整棵树 ,直接输出$query\underline\ min(1,n)$就好了。
2. 如果$LCA(now,root)!=now$,这时根与$now$没有关系,直接查询$now$的子树即可。
3. 如果$LCA(now,root)==now$,这时比较麻烦。
我们可以先找一下$now$的所有儿子。
由于一个子树的$dfs$序是连续的。
所以,如果这个儿子的$id$小于等于$id[root]$,并且这个子树中的最大$dfs$序($id[son]+size[son]-1$)大于等于当前的$id[root]$。
那么就可以判断出$root$在这个儿子中或者就是这个儿子,记录下这个儿子。
还是那句话 :一个子树的$dfs$序是连续的。
这时$now$的子树就是去除包含$root$的那个儿子的子树的整棵树了。
当然,这题也可以用$LCT$维护子树信息做,只不过我不会啊。。。
附代码:
#include<iostream>
#include<algorithm>
#include<cstdio>
#define LSON rt<<1
#define RSON rt<<1|1
#define DATA(x) b[x].data
#define SIGN(x) b[x].c
#define LSIDE(x) b[x].l
#define RSIDE(x) b[x].r
#define WITDH(x) (RSIDE(x)-LSIDE(x)+1)
#define MAXN 100010
#define MAX (1LL<<62)
using namespace std;
int n,m,c=1,d=1,root;
int val[MAXN],head[MAXN],deep[MAXN],son[MAXN],size[MAXN],fa[MAXN],id[MAXN],pos[MAXN],top[MAXN];
struct Tree{
    int next,to;
}a[MAXN<<1];
struct Segmeng_Tree{
    long long data,c;
    int l,r;
}b[MAXN<<2];
inline int read(){
    int date=0,w=1;char c=0;
    while(c<'0'||c>'9'){if(c=='-')w=-1;c=getchar();}
    while(c>='0'&&c<='9'){date=date*10+c-'0';c=getchar();}
    return date*w;
}
inline void pushup(int rt){
    DATA(rt)=min(DATA(LSON),DATA(RSON));
}
inline void pushdown(int rt){
    if(SIGN(rt)==-1||LSIDE(rt)==RSIDE(rt))return;
    SIGN(LSON)=DATA(LSON)=SIGN(rt);
    SIGN(RSON)=DATA(RSON)=SIGN(rt);
    SIGN(rt)=-1;
}
void buildtree(int l,int r,int rt){
    LSIDE(rt)=l;RSIDE(rt)=r;SIGN(rt)=-1;
    if(l==r){
        DATA(rt)=val[pos[l]];
        return;
    }
    int mid=l+r>>1;
    buildtree(l,mid,LSON);
    buildtree(mid+1,r,RSON);
    pushup(rt);
}
void update(int l,int r,long long c,int rt){
    if(l<=LSIDE(rt)&&RSIDE(rt)<=r){
        SIGN(rt)=DATA(rt)=c;
        return;
    }
    pushdown(rt);
    int mid=LSIDE(rt)+RSIDE(rt)>>1;
    if(l<=mid)update(l,r,c,LSON);
    if(mid<r)update(l,r,c,RSON);
    pushup(rt);
}
long long query(int l,int r,int rt){
    long long ans=MAX;
    if(l<=LSIDE(rt)&&RSIDE(rt)<=r)return DATA(rt);
    pushdown(rt);
    int mid=LSIDE(rt)+RSIDE(rt)>>1;
    if(l<=mid)ans=min(ans,query(l,r,LSON));
    if(mid<r)ans=min(ans,query(l,r,RSON));
    return ans;
}
inline void add(int x,int y){
    a[c].to=y;a[c].next=head[x];head[x]=c++;
    a[c].to=x;a[c].next=head[y];head[y]=c++;
}
void dfs1(int rt){
    son[rt]=0;size[rt]=1;
    for(int i=head[rt];i;i=a[i].next){
        int will=a[i].to;
        if(!deep[will]){
            deep[will]=deep[rt]+1;
            fa[will]=rt;
            dfs1(will);
            size[rt]+=size[will];
            if(size[son[rt]]<size[will])son[rt]=will;
        }
    }
}
void dfs2(int rt,int f){
    id[rt]=d++;pos[id[rt]]=rt;top[rt]=f;
    if(son[rt])dfs2(son[rt],f);
    for(int i=head[rt];i;i=a[i].next){
        int will=a[i].to;
        if(will!=fa[rt]&&will!=son[rt])dfs2(will,will);
    }
}
int LCA(int x,int y){
    while(top[x]!=top[y]){
        if(deep[top[x]]<deep[top[y]])swap(x,y);
        x=fa[top[x]];
    }
    if(deep[x]>deep[y])swap(x,y);
    return x;
}
void solve_update(int x,int y,int k){
    while(top[x]!=top[y]){
        if(deep[top[x]]<deep[top[y]])swap(x,y);
        update(id[top[x]],id[x],k,1);
        x=fa[top[x]];
    }
    if(deep[x]>deep[y])swap(x,y);
    update(id[x],id[y],k,1);
}
void solve_query(int x){
    if(x==root)printf("%lld\n",query(1,n,1));
    else{
        int lca=LCA(x,root);
        if(lca==x){
            int y;
            for(int i=head[x];i;i=a[i].next){
                int will=a[i].to;
                if(id[will]<=id[root]&&id[root]<=id[will]+size[will]-1){y=will;break;}
            }
            long long s=min(query(1,id[y]-1,1),query(id[y]+size[y],n,1));
            printf("%lld\n",s);
        }
        else printf("%lld\n",query(id[x],id[x]+size[x]-1,1));
    }
}
void work(){
    int f,x,y,k;
    while(m--){
        f=read();x=read();
        if(f==1){
            root=x;
        }
        else if(f==2){
            y=read();k=read();
            solve_update(x,y,k);
        }
        else solve_query(x);
    }
}
void init(){
    int x,y;
    n=read();m=read();
    for(int i=1;i<n;i++){
        x=read();y=read();
        add(x,y);
    }
    for(int i=1;i<=n;i++)val[i]=read();
    root=read();
    deep[1]=1;
    dfs1(1);
    dfs2(1,1);
    buildtree(1,n,1);
}
int main(){
    init();
    work();
    return 0;
}

 

posted @ 2018-08-13 22:44  符拉迪沃斯托克  阅读(322)  评论(0编辑  收藏  举报
Live2D