zoukankan      html  css  js  c++  java
  • [CF1083C]Max Mex


    题解

    题目就是求树上路径的最大(Mex)
    直接在树上维护这些东西难度有点大
    但是(Mex)表示的是最小的没有出现过的自然数
    这样我们就可以按照数为下标建立线段树
    那么一个代表([l,r])的线段树节点就代表了([l,r])之间的这些数能否构成一条路径
    注意:这里的能构成路径不是恰好能形成一条路径,而是不能确定一定不能形成一条路径
    那么线段树的每个节点就还需要维护链的两个端点
    然后合并信息的时候就是分类讨论
    枚举两个端点,看剩下的两个点是否在这条路径上
    就大致这么判断

    return ((((LCA(x , u) == x) ^ (LCA(x , v) == x)) || LCA(u , v) == x) && (((LCA(y , u) == y) ^ (LCA(y , v) == y)) || LCA(u , v) == y)) ;
    

    然后查询的时候就在线段树上二分
    找到最晚的无法构成路径的数即为答案

    代码

    #include<vector>
    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    const int M = 400005 ;
    using namespace std ;
    
    inline int read() {
        char c = getchar() ; int x = 0 , w = 1 ;
        while(c>'9'||c<'0') { if(c=='-') w = -1 ; c = getchar() ; }
        while(c>='0'&&c<='9') { x = x*10+c-'0' ; c = getchar() ; }
        return x*w ;
    }
    
    int n ;
    int val[M] , fa[M] , pos[M] , lg[M * 2] ;
    int cnt , stp[M] , edp[M] , dep[M] ,  st[M * 2][21] , ans ;
    vector < int > vec[M] ;
    inline void add_edge(int u , int v) { 
        vec[u].push_back(v) ;
    }
    inline int Mindep(int u , int v) { return dep[u] < dep[v] ? u : v ; }
    inline int Maxdep(int u , int v) { return dep[u] > dep[v] ? u : v ; }
    void dfs(int u , int father) {
        stp[u] = edp[u] = ++ cnt ; dep[u] = dep[father] + 1 ;  st[cnt][0] = u ;
        for(int i = 0 , v ; i < vec[u].size() ; i ++) {
            v = vec[u][i] ; if(v == father) continue ;
            dfs(v , u) ; st[++cnt][0] = u ; edp[u] = cnt ;
        }
    }
    inline int LCA(int x , int y) {
        if(dep[x] > dep[y]) swap(x , y) ;
        int l = stp[x] , r = edp[y] ;
        if(l > r) swap(l , r) ;
        int j = lg[r - l + 1] ;
        return Mindep( st[l][j] , st[r - (1 << j) + 1][j] ) ;
    }
    inline bool On(int u , int v , int x , int y) {
        return ((((LCA(x , u) == x) ^ (LCA(x , v) == x)) || LCA(u , v) == x) && (((LCA(y , u) == y) ^ (LCA(y , v) == y)) || LCA(u , v) == y)) ;
    }
    # define ls (now << 1)
    # define rs (now << 1 | 1)
    struct Node {
        bool exist ;
        int lp , rp ;
    } t[M * 4] , tmp ;
    inline Node Merge(Node p1 , Node p2) {
        Node p ; p.lp = p.rp = -1 ; p.exist = false ;
        int lp1 = p1.lp , rp1 = p1.rp , lp2 = p2.lp , rp2 = p2.rp ;
        if(On(lp1 , rp1 , lp2 , rp2)) p.exist = true , p.lp = lp1 , p.rp = rp1 ;
        else if(On(lp2 , rp2 , lp1 , rp1)) p.exist = true , p.lp = lp2 , p.rp = rp2 ;
        else if(On(lp1 , lp2 , rp1 , rp2)) p.exist = true , p.lp = lp1 , p.rp = lp2 ;
        else if(On(lp1 , rp2 , lp2 , rp1)) p.exist = true , p.lp = lp1 , p.rp = rp2 ;
        else if(On(rp1 , lp2 , lp1 , rp2)) p.exist = true , p.lp = rp1 , p.rp = lp2 ;
        else if(On(rp1 , rp2 , lp1 , lp2)) p.exist = true , p.lp = rp1 , p.rp = rp2 ;
        return p ;
    }
    void build(int l , int r , int now) {
        if(l == r) {
            t[now].exist = true ;
            t[now].lp = t[now].rp = pos[l] ;
            return ;
        }
        int mid = (l + r) >> 1 ;
        build(l , mid , ls) ;
        build(mid + 1 , r , rs) ;
        t[now] = Merge(t[ls] , t[rs]) ;
    }
    void Change(int x , int k , int l , int r , int now) {
        if(l == r) {
            t[now].lp = t[now].rp = k ;
            t[now].exist = true ; return ;
        }
        int mid = (l + r) >> 1 ;
        if(mid >= x) Change(x , k , l , mid , ls) ;
        else Change(x , k , mid + 1 , r , rs) ;
        t[now] = Merge(t[ls] , t[rs]) ;
    }
    void qry(int l , int r , int now) {
        if(l == r) {
            if( tmp.lp == -1 || Merge(tmp , t[now]).exist ) {
                ans = max(ans , l) ;
                if(tmp.lp != -1) tmp = Merge(tmp , t[now]) ;
                else tmp = t[now] ;
            }
            return ;
        }
        int mid = (l + r) >> 1 ;
        if(t[ls].exist && (tmp.lp == -1 || Merge(tmp , t[ls]).exist)) {
            if(tmp.lp != -1) tmp = Merge(tmp , t[ls]) ;
            else tmp = t[ls] ;
            tmp.exist = true ;
            ans = max(ans , mid) ;
            qry(mid + 1 , r , rs) ;
        }
        else qry(l , mid , ls) ;
    }
    # undef ls
    # undef rs
    
    int main() {
        n = read() ;
        for(int i = 2 ; i <= n * 2 ; i ++)
            lg[i] = lg[i >> 1] + 1 ;
        for(int i = 1 ; i <= n ; i ++) {
            val[i] = read() ;
            pos[val[i]] = i ;
        }
        for(int i = 2 ; i <= n ; i ++) {
            fa[i] = read() ;
            add_edge(fa[i] , i) ;
        }
        dfs(1 , 1) ;
        for(int j = 1 ; j <= lg[n * 2] ; j ++)
            for(int i = 1 ; i + (1 << j) - 1 <= n * 2 ; i ++)
                st[i][j] = Mindep( st[i][j - 1] , st[i + (1 << (j - 1))][j - 1] ) ;
        build(0 , n - 1 , 1) ;
        int Q = read() , opt , x , y ;
        while(Q --) {
            opt = read() ;
            if(opt == 1) {
                x = read() ; y = read() ;
                Change(val[x] , pos[val[y]] , 0 , n - 1 , 1) ;
                Change(val[y] , pos[val[x]] , 0 , n - 1 , 1) ;
                swap(pos[val[x]] , pos[val[y]]) ;
                swap(val[x] , val[y]) ;
            } 
            else {
                ans = 0 ;
                tmp.lp = tmp.rp = -1 ;
                tmp.exist = true ;
                qry(0 , n - 1 , 1) ;
                printf("%d
    ",ans + 1) ;
            }
        }
        return 0 ;
    }
    
    
  • 相关阅读:
    如何阅读一个Web项目 【转载】
    线程的状态与基本操作
    java多线程通信方式之一:wait/notify
    synchronized的简单理解
    每月IT摘录201807
    springmvc 请求无法到达controller,出现404
    android开发 java与c# 兼容AES加密
    android 开发不能创建目录
    mysql存储过程出现OUT or INOUT argument 10 for routine
    android退出登陆后,清空之前所有的activity,进入登陆主界面
  • 原文地址:https://www.cnblogs.com/beretty/p/10726029.html
Copyright © 2011-2022 走看看