码迷,mamicode.com
首页 > 其他好文 > 详细

[CF1083C]Max Mex

时间:2019-04-17 20:59:45      阅读:160      评论:0      收藏:0      [点我收藏+]

标签:nod   vector   back   main   ||   struct   判断   src   枚举   

技术图片


题解

题目就是求树上路径的最大\(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\n",ans + 1) ;
        }
    }
    return 0 ;
}

[CF1083C]Max Mex

标签:nod   vector   back   main   ||   struct   判断   src   枚举   

原文地址:https://www.cnblogs.com/beretty/p/10726029.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!