ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

CF1017G The Tree

2020-09-23 22:36:10  阅读:207  来源: 互联网

标签:CF1017G qr int tr void Tree ls ql


CF1017G The Tree

给定一棵树,三种操作:

  1. 将 \(x\) 染黑,如果其为黑色,那么对子树递归。
  2. 将 \(x\) 的子树染白。
  3. 查询 \(x\) 的颜色。

\(n,m\le 10^5\)

Solution

考虑链的情况怎么做。

不考虑操作 \(2\),假设已知我们进行了若干次操作 \(1\),如何判定点 \(x\) 的颜色。

假设某个点执行了操作 \(2\) 那么给其权值 \(+1\),那么考虑从某个 \(u<x\) 处起,如果直到 \(x\) 这一段区间的点权和大于 \(u\to x\) 的距离那么显然就是可以的。

于是条件等价于 \(\exist ~u<x,dis_x-dis_u\le w_x-w_u\) 即 \(\min(w_u-dis_u)\le w_x-dis_x\)

这个做法是可以拓展到树上的。

接下来考虑操作 \(2\),我们发现我们不好删除之前的操作 \(1\) 的影响。

那么不妨认为操作 \(2\) 带来了独立的影响!我们先清空子树内的增加权值,再给 \(x\) 处增加一个负点权,使得 \(x\) 处的答案刚好被消去即可。设增加的权值为 \(c\),那么我们希望的是不存在 \(u\) 满足 \(dis_x-dis_u\le w_x-w_u\)

即 \(dis_x-dis_u> w_x-w_u+c,w_u-dis_u>w_x-dis_x+c\),故 \(c\) 即两者差减 \(1\) 和 \(0\) 取 \(\max\)。

不难发现其正确性,这个算法可以刚好使得 \(2\) 的影响为消去子树贡献。

于是我们只需要支持:查询链上最大值,和子树修改,单点修改,单点查询等操作。

可以通过树链剖分来解决这个问题,复杂度为 \(\mathcal O(m\log^2 n)\)


还有一个非常仙的做法:

考虑对查询进行分块,设块的大小为 \(cnt\),现在将一个块内的所有查询涉及到的点拿出来建虚树。

这样我们得到了一个大小为 \(cnt\) 的树。

对于每条边,维护边上的点数,和边上白色点的数量。

考虑修改,对于操作 \(1\) 暴力修改即可,注意维护边上的信息。

对于操作 \(2\),暴力清空子树边上的白色点数量为原点数。

对于查询,直接输出即可。

每处理完一个块之后,我们通过 Dfs 暴力重构这棵树即可。

复杂度为 \(\mathcal O(n\cdot cnt+\frac{n^2}{cnt})\),平衡可以做到 \(\mathcal O(n\sqrt{n})\)(这里认为 \(n,q\) 同级别)

这里的建虚树是通过 Dfs 建的。

\(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 inf = 1e9 + 5 ; 
const int N = 2e5 + 5 ;
int n, q, idnex, L[N], R[N], Id[N] ;
int top[N], f[N], dep[N], sz[N], son[N] ;
vector<int> G[N] ; 
struct Tr { int w, c, tag, mark ; } tr[N << 2] ;
void dfs1(int x, int fa) {
	f[x] = fa, dep[x] = dep[fa] + 1, sz[x] = 1 ;
	for(int v : G[x]) {
		dfs1(v, x), sz[x] += sz[v] ;
		if( sz[v] > sz[son[x]] ) son[x] = v ; 
	} 
}
void dfs2(int x, int high) {
	top[x] = high, L[x] = ++ idnex, Id[idnex] = x ; 
	if(son[x]) dfs2(son[x], high) ;
	for(int v : G[x]) if( v ^ son[x] ) dfs2(v, v) ;
	R[x] = idnex ; 
}
void pushup(int x) { tr[x].w = min(tr[ls(x)].w, tr[rs(x)].w ) ; }
void Col(int x) {
	tr[x].mark = 1, tr[x].w = tr[x].c, tr[x].tag = 0 ; 
}
void pushmark(int x) {
	if( tr[x].mark ) Col(ls(x)), Col(rs(x)), tr[x].mark = 0 ; 
	int s = tr[x].tag ; tr[x].tag = 0 ;
	tr[ls(x)].tag += s, tr[rs(x)].tag += s,
	tr[ls(x)].w += s, tr[rs(x)].w += s ;  
}
void build(int x, int l, int r) {
	if( l == r ) return tr[x].w = tr[x].c = -dep[Id[l]], void() ;
	int mid = (l + r) >> 1 ; 
	build(ls(x), l, mid), build(rs(x), mid + 1, r), pushup(x), tr[x].c = tr[x].w ; 
}
void Cover(int x, int l, int r, int ql, int qr) {
	if( ql <= l && r <= qr ) return Col(x), void() ; 
	if( qr < l || r < ql ) return ; 
	int mid = (l + r) >> 1 ; pushmark(x) ; 
	Cover(ls(x), l, mid, ql, qr), Cover(rs(x), mid + 1, r, ql, qr), pushup(x) ; 
}
void update(int x, int l, int r, int ql, int qr, int k) {
	if( ql <= l && r <= qr ) return tr[x].w += k, tr[x].tag += k, void() ; 
	if( qr < l || r < ql ) return ; 
	int mid = (l + r) >> 1 ; pushmark(x) ; 
	update(ls(x), l, mid, ql, qr, k), 
	update(rs(x), mid + 1, r, ql, qr, k), pushup(x) ; 
}
int query(int x, int l, int r, int ql, int qr) {
	if( ql <= l && r <= qr ) return tr[x].w ; 
	if( qr < l || r < ql ) return 0 ;
	int mid = (l + r) >> 1 ; pushmark(x) ;
	return min(query(ls(x), l, mid, ql, qr), query(rs(x), mid + 1, r, ql, qr)) ; 
}
int Q(int x) { 
	int ans = inf ; 
	while( x != 1 ) ans = min( ans, query( 1, 1, n, L[top[x]], L[x]) ), x = f[top[x]] ; 
	ans = min( ans, query(1, 1, n, L[top[x]], L[x]) ) ;
	return ans ; 
}
void White(int x) {
	Cover(1, 1, n, L[x], R[x]) ; 
	int c = Q(f[x]), w = query(1, 1, n, L[x], L[x]) ; 
	c = max( 0, c - w - 1 ), update(1, 1, n, L[x], R[x], c) ; 
}
void Query(int x) {
	int c = Q(f[x]), w = query(1, 1, n, L[x], L[x]) ; 
	if( c <= w ) puts("black") ;
	else puts("white") ; 
} 
signed main()
{
	n = gi() + 1, q = gi() ; int opt, x ; 
	rep( i, 3, n ) x = gi() + 1, G[x].push_back(i) ; 
	G[1].push_back(2) ; 
	dfs1(1, 1), dfs2(1, 1), build(1, 1, n) ;
	rep( i, 1, q ) {
		opt = gi(), x = gi() + 1 ; 
		if( opt == 1 ) update(1, 1, n, L[x], R[x], 1) ;
		if( opt == 2 ) White(x) ; 
		if( opt == 3 ) Query(x) ;  
	}
	return 0 ;
}

标签:CF1017G,qr,int,tr,void,Tree,ls,ql
来源: https://www.cnblogs.com/Soulist/p/13721490.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有