BZOJ 3083: 遥远的国度 [树链剖分 DFS序 LCA]

3083: 遥远的国度

Time Limit: 10 Sec  Memory Limit: 1280 MB
Submit: 3127  Solved: 795
[Submit][Status][Discuss]

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。

HINT

 

Source

zhonghaoxi提供


 

这么快A掉好高兴

 

没有换根,不就是dfs剖分裸题嘛?

加上换根后,发现换根后树形态不变,两点之间路径不变,并且有些子树也没变

对于询问分类讨论

x==rt 查询[1,n](注意这里要特判,一开始没有处理)

x在rt的子树内,子树没有变

x不在rt到原根的链上,子树没有变

x在rt到原根的链上,(即x=lca(x,rt)),发现现在x的子树就是整棵树减去x往rt方向向下那个节点的子树,于是倍增求那个点然后整个dfs序就是分成两段了啊

 

dfs的问题:没有必要出栈单独,最后一种情况就是[1,L[v]-1]和[R[v]+1,n]

 

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
#define lc o<<1
#define rc o<<1|1
#define m ((l+r)>>1)
#define lson o<<1,l,m
#define rson o<<1|1,m+1,r
const int N=1e5+5,INF=2147483647;
typedef long long ll;
inline int read(){
    char c=getchar();int x=0,f=1;
    while(c<'0'||c>'9'){if(c=='-')f=-1; c=getchar();}
    while(c>='0'&&c<='9'){x=x*10+c-'0'; c=getchar();}
    return x*f;
}
int n,Q,rt,w[N],fw[N],op,a,b,v;
struct edge{
    int v,ne;
}e[N<<1];
int cnt,h[N];
inline void ins(int u,int v){
    cnt++;
    e[cnt].v=v;e[cnt].ne=h[u];h[u]=cnt;
    cnt++;
    e[cnt].v=u;e[cnt].ne=h[v];h[v]=cnt;
}
int deep[N],fa[N][20],tid[N],top[N],tot,size[N],mx[N];
int L[N],R[N];
void dfs(int u){
    size[u]=1;
    for(int i=h[u];i;i=e[i].ne){
        int v=e[i].v;
        if(v==fa[u][0]) continue;
        fa[v][0]=u;deep[v]=deep[u]+1;
        dfs(v);
        size[u]+=size[v];
        if(size[v]>size[mx[u]]) mx[u]=v;
    }
}
void dfs(int u,int anc){
    if(!u) return;
    tid[u]=L[u]=++tot;
    top[u]=anc;
    for(int j=1;(1<<j)<=deep[u];j++)
        fa[u][j]=fa[fa[u][j-1]][j-1];
    dfs(mx[u],anc);
    for(int i=h[u];i;i=e[i].ne)
        if(e[i].v!=fa[u][0]&&e[i].v!=mx[u]) dfs(e[i].v,e[i].v);
    R[u]=tot;
}
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]][0];
    }
    if(deep[x]>deep[y]) swap(x,y);
    return x;
}

struct node{
    int mn,set;
}t[N<<2];
inline void merge(int o){
    t[o].mn=min(t[lc].mn,t[rc].mn);
}
inline void paint(int o,int v){
    t[o].mn=t[o].set=v;
}
inline void pushDown(int o){
    if(t[o].set){
        paint(lc,t[o].set);
        paint(rc,t[o].set);
        t[o].set=0;
    }
}
void build(int o,int l,int r){
    if(l==r) paint(o,w[l]);
    else{
        build(lson);
        build(rson);
        merge(o);
    }
}
void segCha(int o,int l,int r,int ql,int qr,int v){
    if(ql<=l&&r<=qr) paint(o,v);
    else{
        pushDown(o);
        if(ql<=m) segCha(lson,ql,qr,v);
        if(m<qr) segCha(rson,ql,qr,v);
        merge(o);
    }
}
int segQue(int o,int l,int r,int ql,int qr){
    if(ql<=l&&r<=qr) return t[o].mn;
    else{
        pushDown(o);
        int mn=INF;
        if(ql<=m) mn=min(mn,segQue(lson,ql,qr));
        if(m<qr) mn=min(mn,segQue(rson,ql,qr));
        return mn;     
    }
}

void change(int x,int y,int v){
    while(top[x]!=top[y]){
        if(deep[top[x]]<deep[top[y]]) swap(x,y);
        segCha(1,1,n,tid[top[x]],tid[x],v);
        x=fa[top[x]][0];
    }
    if(tid[x]>tid[y]) swap(x,y);
    segCha(1,1,n,tid[x],tid[y],v);
}

int jump2anc(int x,int d){
    int bin=deep[x]-d;
    for(int j=0;j<=17;j++) 
        if((1<<j)&bin) x=fa[x][j];
    return x;
}
int query(int x){
    if(x==rt) return segQue(1,1,n,1,n);
    else if(L[rt]<=tid[x]&&tid[x]<=R[rt]) return segQue(1,1,n,L[x],R[x]);
    else{
        int p=lca(x,rt);
        if(x!=p) return segQue(1,1,n,L[x],R[x]);
        else{
            int v=jump2anc(rt,deep[x]+1);
            return min(segQue(1,1,n,R[v]+1,n),segQue(1,1,n,1,L[v]-1));
        }
    }
}

int main(){
    //freopen("in.txt","r",stdin);
    n=read();Q=read();
    for(int i=1;i<=n-1;i++) a=read(),b=read(),ins(a,b);
    for(int i=1;i<=n;i++) fw[i]=read();
    rt=read();
    dfs(rt);dfs(rt,rt);
    for(int i=1;i<=n;i++) w[tid[i]]=fw[i];//,printf("hi %d %d %d  %d %d\n",i,tid[i],w[tid[i]],L[i],R[i]);
    build(1,1,n);
    
    while(Q--){
        op=read();
        if(op==1) rt=read();
        else if(op==3) printf("%d\n",query(read()));
        else{
            a=read();b=read();v=read();
            change(a,b,v);
        }
    }
}

 

posted @ 2017-01-04 21:26  Candy?  阅读(1029)  评论(0编辑  收藏  举报