• CF1416D Graph and Queries


    CF1416D Graph and Queries

    给定 (n) 个点,(m) 条边的无向图,点有点权 (p_i) 构成一个排列 (1sim n)

    执行 (q) 次操作:

    1. 查询 (v) 能够到达的点中,(p_u) 最大的点 (u),然后将 (p_u) 设为 (0)
    2. 删除第 (i) 条边。

    (nle 2cdot 10^5,mle 3cdot 10^5,qle 5cdot 10^5)

    Solution

    按照时间建 Kruskal 重构树,点 (u) 能够到达 (v) 等价于沿途时间大于当前查询。

    每个点维护 Dfs 序的一个区间,在线段树上区间修改即可,复杂度 (mathcal O(nlog n))(假设平级)

    感觉这个题对重构树的使用挺自然的,当你尝试了反向操作等奇怪 trick 后发现都无法成功,是时候按照时间赋权值了。

    不过 (v) 能够到达的点中,这个条件略有提示意义。

    (Code:)

    #include<bits/stdc++.h>
    using namespace std ;
    #define Next( i, x ) for( register int i = head[x]; i; i = e[i].next )
    #define rep( i, s, t ) for( register int i = (s); i <= (t); ++ i )
    #define drep( i, s, t ) for( register int i = (t); i >= (s); -- i )
    #define re register
    #define ls(x) (x << 1)
    #define rs(x) (x << 1 | 1)
    int gi() {
    	char cc = getchar() ; int cn = 0, flus = 1 ;
    	while( cc < '0' || cc > '9' ) {  if( cc == '-' ) flus = - flus ; cc = getchar() ; }
    	while( cc >= '0' && cc <= '9' )  cn = cn * 10 + cc - '0', cc = getchar() ;
    	return cn * flus ;
    }
    const int N = 5e5 + 5 ; 
    int n, m, t, p[N], fa[N], f[N][20], L[N], R[N], Id[N], w[N], num  ; 
    vector<int> G[N] ;  
    struct E {
    	int fr, to, t ; 
    } e[N << 1] ;
    struct Q {
    	int opt, x ; 
    } q[N] ;
    bool cmp( E x, E y ) {
    	return x.t > y.t ; 
    }
    int fd(int x) {
    	return (fa[x] != x) ? fa[x] = fd(fa[x]) : x ; 
    }
    void add(int x, int y) {
    	G[x].push_back(y) ; 
    }
    void Dfs(int x, int ff) {
    	f[x][0] = ff ; 
    	rep( i, 1, 17 ) f[x][i] = f[f[x][i - 1]][i - 1] ; 
    	if( x <= n ) return L[x] = R[x] = ++ num, Id[num] = x, void() ; 
    	L[x] = n + 1 ; 
    	for(int v : G[x]) Dfs(v, x), L[x] = min(L[x], L[v]) ;
    	R[x] = num ; 
    }
    void Kruskal() {
    	sort( e + 1, e + m + 1, cmp ) ; 
    	rep( i, 1, n ) fa[i] = i ; int idx = n ;
    	rep( i, 1, m ) {
    		int x = e[i].fr, y = e[i].to ; 
    		int u = fd(x), v = fd(y) ;
    		if( u == v ) continue ; 
    		++ idx, add(idx, u), add(idx, v),
    		fa[u] = fa[v] = idx, fa[idx] = idx, w[idx] = e[i].t ; 
    	} 
    	rep( i, 1, idx ) if( fa[i] == i ) add(idx + 1, i) ; 
    	Dfs(idx + 1, idx + 1) ; 
    }
    struct Tr {
    	int mx, id ; 
    } tr[N << 2], Zero ; 
    Tr pushup(Tr l, Tr r) {
    	return ( r.mx > l.mx ) ? r : l ; 
    } 
    void build(int x, int l, int r) {
    	if( l == r ) return tr[x].mx = p[Id[l]], tr[x].id = Id[l], void() ; 
    	int mid = (l + r) >> 1 ; 
    	build(ls(x), l, mid), build(rs(x), mid + 1, r) ;
    	tr[x] = pushup(tr[ls(x)], tr[rs(x)]) ;
    }
    Tr query(int x, int l, int r, int ql, int qr) {
    	if( ql <= l && r <= qr ) return tr[x] ;
    	if( l > qr || r < ql ) return Zero ; 
    	int mid = (l + r) >> 1 ; 
    	return pushup(query(ls(x), l, mid, ql, qr), query(rs(x), mid + 1, r, ql, qr)) ; 
    }
    void update(int x, int l, int r, int k ) {
    	if( l == r ) return tr[x].mx = 0, void() ;
    	int mid = (l + r) >> 1 ; 
    	if( k <= mid ) update(ls(x), l, mid, k) ;
    	else update(rs(x), mid + 1, r, k) ;
    	tr[x] = pushup(tr[ls(x)], tr[rs(x)]) ; 
    }
    signed main()
    {
    	n = gi(), m = gi(), t = gi() ; int x, y ; 
    	rep( i, 1, n ) p[i] = gi() ; 
    	rep( i, 1, m ) 
    		x = gi(), y = gi(), e[i] = (E){x, y, t + 1} ; 
    	rep( i, 1, t ) {
    		q[i].opt = gi(), q[i].x = gi() ;
    		if( q[i].opt == 2 ) e[q[i].x].t = i ; 
    	}
    	Kruskal(), Zero.mx = Zero.id = 0, build(1, 1, n) ;
    	rep( i, 1, t ) {
    		if( q[i].opt == 2 ) continue ; 
    		int u = q[i].x ; 
    		drep( j, 0, 17 ) if( w[f[u][j]] >= i ) u = f[u][j] ;
    		Tr ans = query(1, 1, n, L[u], R[u]) ; 
    		if( ans.mx == 0 ) puts("0") ;
    		else printf("%d
    ", ans.mx ), update(1, 1, n, L[ans.id]) ; 
    	}
    	return 0 ;
    }
    
  • 相关阅读:
    数据结构上机思考
    hdu1005,循环节
    网络赛总结
    icpc沈阳网络赛。cake cake!
    树的基础代码
    网络赛第一场
    欧拉函数
    欧拉函数
    多校第十场
    (环上)最大子段和
  • 原文地址:https://www.cnblogs.com/Soulist/p/13749149.html
Copyright © 2020-2023  润新知