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 ;
}
原文地址:https://www.cnblogs.com/Soulist/p/13749149.html