【Bzoj3083】遥远的国度

14 篇文章 0 订阅
12 篇文章 0 订阅

题意

给定一棵有根树,支持3种操作:
1.把首都修改为id;
2.将p1 p2路径上的所有城市的防御值修改为v;
3.询问以城市id为根的子树中的最小防御值。


分析

画了一堆图之后终于搞懂了一点点,首先换根的话肯定不是真的换。对于每次询问,设现在的根为root,准备询问的结点为x。来考虑几种情况。
1.root == x ,询问整棵树,直接输出全集。
2.root不为x的子树,则直接考虑x的整棵子树。
3.root为x的子树(也可能是x的某子树中的结点),则不能考虑x的这棵子树,就直接抹去这一段考虑其补集,边界条件的话要注意,不然可能RE。


#include <cstdio>
#include <algorithm>
#include <cstring>

#define Rep(i,s,t) for(int i=s;i<=t;i++)
#define For(i,s,t) for(int i=s;i;i=t)

using namespace std;

const int maxx = 100000 + 25;
const int Inf = (unsigned)(-1) >> 1;

int head[maxx],nxt[maxx<<1],to[maxx<<1];
int top[maxx],rnk[maxx],size[maxx],ftr[maxx],son[maxx],dpt[maxx];
int a[maxx],T[maxx<<2],Add[maxx<<2],fnl[maxx];

int n,m,num,f,cnt,x,y,z,root;

namespace Y{

    void Ins(int x,int y){to[++num]=y;nxt[num]=head[x];head[x]=num;}

    void Dfs1(int x){
        size[x] = 1;
        For( i , head[x] , nxt[i] ){
            int now = to[i];if(now == ftr[x]) continue;
            ftr[now] = x;dpt[now] = dpt[x] + 1;
            Dfs1(now);size[x] += size[now];
            if(size[now] > size[son[x]]) son[x] = now;
        }
    }

    void Dfs2(int x,int brn){
        rnk[x] = ++cnt;top[x] = brn;
        if(son[x]) Dfs2(son[x],brn);
        For( i , head[x] , nxt[i] )
            if(to[i] != ftr[x] && to[i] != son[x])
                Dfs2(to[i],to[i]);
        fnl[x] = cnt;
    }

    void pushdown(int i){
        T[i<<1] = T[i<<1|1] = Add[i<<1] = Add[i<<1|1] = Add[i];
        Add[i] = 0;
    }

    void modify(int i,int x,int y,int l,int r,int k){
        if(x<=l && r<=y) {T[i] = Add[i] = k;return;}
        if(Add[i]) pushdown(i);int mid = (l+r) >> 1;
        if(x <= mid) modify(i<<1,x,y,l,mid,k);
        if(y >  mid) modify(i<<1|1,x,y,mid+1,r,k);
        T[i] = min(T[i<<1],T[i<<1|1]);
    }

    int Query(int i,int x,int y,int l,int r){
        if(x<=l && r<=y) return T[i];int ans = Inf;
        if(Add[i]) pushdown(i);int mid = (l+r) >> 1;
        if(x <= mid) ans = min(ans,Query(i<<1,x,y,l,mid));
        if(y >  mid) ans = min(ans,Query(i<<1|1,x,y,mid+1,r));
        return ans;
    }

    void update(int x,int y,int k){
        while(top[x] != top[y]){
            if(dpt[top[x]] > dpt[top[y]]) x^=y^=x^=y;
            modify(1,rnk[top[y]],rnk[y],1,n,k);
            y = ftr[top[y]];
        }
        if(rnk[x] > rnk[y]) x^=y^=x^=y;
        modify(1,rnk[x],rnk[y],1,n,k);
    }

    int Get(int x){
        if(x == root) return Query(1,1,n,1,n);
        if(rnk[root] < rnk[x] || rnk[root] > fnl[x])
            return Query(1,rnk[x],fnl[x],1,n);
        int ans = Inf,i;
        for(i=head[x];i;i=nxt[i])
            if(to[i] != ftr[x] && rnk[root] >= rnk[to[i]] && rnk[root] <= fnl[to[i]])
                break;
        ans = min(ans,Query(1,1,rnk[to[i]]-1,1,n));
        if(fnl[to[i]] != n)
            ans = min(ans,Query(1,fnl[to[i]]+1,n,1,n));
        return ans;
    }

}

using namespace Y;

int main(){
    scanf("%d%d",&n,&m);
    Rep( i , 1 , n-1 ) scanf("%d%d",&x,&y),Ins(x,y),Ins(y,x);
    Rep( i , 1 , n ) scanf("%d",&a[i]);
    scanf("%d",&root);Dfs1(root),Dfs2(root,root);
    Rep( i , 1 , n ) modify(1,rnk[i],rnk[i],1,n,a[i]);
    while( m-- ){
        scanf("%d",&f);
        if(f == 1) scanf("%d",&z),root = z;
        if(f == 2) scanf("%d%d%d",&x,&y,&z),update(x,y,z);
        if(f == 3) scanf("%d",&x),printf("%d\n",Get(x));
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值