zoukankan      html  css  js  c++  java
  • 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。

    Solution

    如果没有换根就是个树剖板子,换根显然不能真的去换,可以对当前根进行分类讨论。

    1.如果询问的节点x就是当前根,那么输出整棵树的答案即可。

    2.如果根在询问的节点x的子树中,那么找出根和节点x之间的那条链上x的儿子(这个用倍增即可处理),询问的答案就是min(query(1,id[y]),query(out[y]+1,n))(如果画张图就能很好的理解了)。

    3.对于根不在x的子树内也不是x的情况,根的位置对x的子树没有任何影响,直接查询即可。

    然而我习惯的不存重儿子的写法不能直接在第二次dfs的时候处理dfs序...需要重新跑一遍循环,为了这个debug了好几个小时...

    #include <bits/stdc++.h>
    
    #define ll long long
    #define inf 0x3f3f3f3f
    #define il inline
    #define int long long 
    
    namespace io {
    
        #define in(a) a=read()
        #define out(a) write(a)
        #define outn(a) out(a),putchar('
    ')
    
        #define I_int int
        inline I_int read() {
            I_int x = 0 , f = 1 ; char c = getchar() ;
            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 ;
        }
        char F[ 200 ] ;
        inline void write( I_int x ) {
            if( x == 0 ) { putchar( '0' ) ; return ; }
            I_int tmp = x > 0 ? x : -x ;
            if( x < 0 ) putchar( '-' ) ;
            int cnt = 0 ;
            while( tmp > 0 ) {
                F[ cnt ++ ] = tmp % 10 + '0' ;
                tmp /= 10 ;
            }
            while( cnt > 0 ) putchar( F[ -- cnt ] ) ;
        }
        #undef I_int
    
    }
    using namespace io ;
    
    #define N 200010
    
    int n = read() , m = read() ;
    int tot , cnt , head[N] , root ;
    struct edge {
        int to , nxt ;
    } e[N << 1] ;
    int dep[N] , siz[N] , last[N] , id[N] , top[N] , fa[N] , w[N] , a[N] ; 
    int f[N][19] , lg2[N] ;
    
    void ins(int u , int v) {
        e[++cnt] = (edge) {v , head[u]} ;
        head[u] = cnt ;
    }
    
    void dfs1(int u) {
        siz[u] = 1 ;
        for(int i = head[u] ; i ; i = e[i].nxt) {
            if(e[i].to == fa[u]) continue ;
            fa[e[i].to] = u ; f[e[i].to][0] = u ;
            dep[e[i].to] = dep[u] + 1 ;
            dfs1(e[i].to) ;
            siz[u] += siz[e[i].to] ;
        }
    }
    
    void dfs2(int u , int topf) {
        top[u] = topf ;
        id[u] = ++ tot ;
        w[tot] = a[u] ;
        int k = 0 ;
        for(int i = head[u]; i ; i = e[i].nxt) {
            if(e[i].to == fa[u]) continue ;
            if(siz[e[i].to] > siz[k]) k = e[i].to ;
        }
        if(!k) return ;
        dfs2(k , topf) ;
        for(int i = head[u]; i ; i = e[i].nxt) {
            if(e[i].to == fa[u] || e[i].to == k) continue ;
            dfs2(e[i].to , e[i].to) ;
        }
    } 
    
    #define rc (rt << 1 | 1)
    #define lc (rt << 1)
    struct tree {
        int l , r , add , min ;
    } t[N<<2] ;
    
    void pushup(int rt) { t[rt].min = std::min(t[lc].min , t[rc].min) ; }
    
    void build(int l , int r , int rt) {
        t[rt].l = l ; t[rt].r = r ; t[rt].min = inf ; int mid = (l + r) >> 1 ;
        if(l == r) {t[rt].min = w[l] ; return ; }
        build(l , mid , lc) ; build(mid + 1 , r , rc) ; pushup(rt) ;
    }
    
    #define l t[rt].l
    #define r t[rt].r
    #define mid ((l+r) >> 1)
    
    void pushdown(int rt) {
        int x = t[rt].add ;
        if(!x) return ; 
        t[lc].min = t[rc].min = t[lc].add = t[rc].add = x ; t[rt].add = 0 ;
    }
    
    void upd(int L , int R , int c , int rt) {
        if(L <= l && r <= R) { t[rt].min = c ; t[rt].add = c ; return ; } 
        pushdown(rt) ;
        if(L <= mid) upd(L , R , c , lc) ; if(R > mid) upd(L , R , c , rc) ;
        pushup(rt) ;
    }
    
    int query(int L , int R , int rt) {
        if(L <= l && r <= R) return t[rt].min ;
        pushdown(rt) ; int ans = 0 ;
        if(L <= mid) ans = query(L , R , lc) ;
        if(R > mid) ans = ans ? std::min(ans , query(L , R , rc)) : query(L , R , rc) ;
        return ans ;
    }
    
    #undef l
    #undef r
    #undef mid
    #undef lc
    #undef rc
    
    void S_upd(int x , int y , int val) {
        while(top[x] != top[y]) {
            if(dep[top[x]] < dep[top[y]]) std::swap(x , y) ;
            upd(id[top[x]] , id[x] , val , 1) ;
            x = fa[top[x]] ;
         }
         if(id[x] > id[y]) std::swap(x , y) ;
         upd(id[x] , id[y] , val , 1) ;
    }
    
    void init() {
        for(int i = 2 ; i <= n ; i ++) lg2[i] = lg2[i>>1] + 1 ;
        for(int j = 1 ; j <= 17 ; j ++) {
            for(int i = 1 ; i <= n ; i ++) {
                f[i][j] = f[ f[i][j - 1] ][j - 1] ;
            }
        }
    }
    
    int getf(int x , int FF) {
        for(int i = lg2[dep[x]] ; i >= 0 ; i --) {
            if(dep[f[x][i]] > dep[FF]) x = f[x][i] ;
        }    
        return x ;
    }
    
    signed main() {
        int ans , pos ;
        for(int i = 1 ; i < n ; i ++) {
            int u = read() , v = read() ;
            ins(u , v) , ins(v , u) ;
        }
        for(int i = 1 ; i <= n ; i ++) a[i] = read() ;
        root = read() ; dep[root] = 1 ;
        dfs1(root) , dfs2(root , root) , init() , build(1 , n , 1);
        for(int i = 1 ; i <= n ; i ++) last[i] = id[i] + siz[i] - 1 ;
        while(m --) {
            int opt = read() , x = read() , y , val ;
            if(opt == 1) root = x ;
            else if(opt == 2) {
                y = read() , val = read() ;
                S_upd(x , y , val) ;
            }
            else {
                if(root == x) ans = t[1].min ;
                else {
                    if(id[x] <= id[root] && last[x] >= last[root]) {
                        ans = (1ll << 60) ; pos = getf(root , x) ;
                        if(id[pos] > 1) ans = query(1 , id[pos] - 1 , 1) ;
                        if(last[pos] < n) ans = std::min(ans , query(last[pos] + 1 , n , 1)) ; 
                    } else ans = query(id[x] , last[x] , 1) ;
                }
                outn(ans) ; 
            }
        }
    //    for(int i = 1 ; i <= n ; i ++) printf("%d " , id[i]) ; puts("") ;
    //    for(int i = 1 ; i <= n ; i ++) printf("%d " , last[i]) ; puts("") ;
    }
  • 相关阅读:
    ReadOnly TextEdit输入问题
    关于正太分布单侧区间上下限的定义
    关于Devexpress richEditControl
    CentOS7 升级 cmake
    极客时间实战目录
    kafka安装
    查找连续相同值的算法,并给出连续相同值的个数以及位置
    解决若依linux启动ERROR
    supervisor配置进程
    python做上位机
  • 原文地址:https://www.cnblogs.com/henry-1202/p/10084648.html
Copyright © 2011-2022 走看看