ICode9

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

BZOj #4771. 七彩树(主席树+dfn序+lca)

2021-09-14 18:06:11  阅读:129  来源: 互联网

标签:int lca dep dfn maxn 4771 root


BZOj #4771. 七彩树

description

给定一棵n个点的有根树,编号依次为1到n,其中1号点是根节点。每个节点都被染上了某一种颜色,其中第i个节点的颜色为c[i]。如果c[i]=c[j],那么我们认为点i和点j拥有相同的颜色。定义depth[i]为i节点与根节点的距离,为了方便起见,你可以认为树上相邻的两个点之间的距离为1。站在这棵色彩斑斓的树前面,你将面临m个问题。

每个问题包含两个整数x和d,表示询问x子树里且depth不超过depth[x]+d的所有点中出现了多少种本质不同的颜色。请写一个程序,快速回答这些询问。

Input

第一行包含一个正整数T(1<=T<=500),表示测试数据的组数。

每组数据中,第一行包含两个正整数n(1<=n<=100000)和m(1<=m<=100000),表示节点数和询问数。

第二行包含n个正整数,其中第i个数为 c [ i ] ( 1 < = c [ i ] < = n ) c[i](1<=c[i]<=n) c[i](1<=c[i]<=n),分别表示每个节点的颜色。

第三行包含n-1个正整数,其中第i个数为 f [ i + 1 ] ( 1 < = f [ i ] < i ) f[i+1](1<=f[i]<i) f[i+1](1<=f[i]<i),表示节点i+1的父亲节点的编号。

接下来m行,每行两个整数x(1<=x<=n)和d(0<=d<n),依次表示每个询问。

输入数据经过了加密,对于每个询问,如果你读入了x和d,那么真实的x和d分别是x xor last和d xor last,

其中last表示这组数据中上一次询问的答案,如果这是当前数据的第一组询问,那么last=0。

输入数据保证n和m的总和不超过500000。

Output

对于每个询问输出一行一个整数,即答案。

Sample Input

1
5 8
1 3 3 2 2
1 1 3 3
1 0
0 0
3 0
1 3
2 1
2 0
6 2
4 1

Sample Output

1
2
3
1
1
2
1
1

solution

询问子树内的问题,通常都转化成dfn序,然后就可以用线段树维护,变成区间问题

询问距离不超过 d e p x + d dep_x+d depx​+d,那就按深度排序后,建主席树

则对于深度为 i i i的版本的线段树只会存在深度 ≤ i \le i ≤i的点

线段树上的点管辖的区间就是其子树

其点存的值,就是管辖区间内不同颜色的个数

最后只需要处理子树内多个点有同样颜色的修改

具体而言,根据dfn序,对于新增点 i i i,在线段树上对应的点进行+1

找到与其颜色相同的dfn小于 i i i的最大dfn序对应的点,记为 i i i的前驱

那么求出这两个点的lca,从lca往上的点都含有这两个点,但只需要算一个,所以在线段树上lca对应的叶子节点,进行-1

同理。找到与其颜色相同的dfn大于 i i i的最小dfn序对应的点,记为 i i i的后继

那么求出这两个点的lca,从lca往上的点都含有这两个点,但只需要算一个,所以在线段树上lca对应的叶子节点,进行-1

但是前驱和后继的lca又多减了 1 1 1,所以要对其进行+1操作

code

#include <set>
#include <cstdio>
#include <iostream>
#include <algorithm>
using namespace std;
#define maxn 100005
set < int > s[maxn];
struct node { int id, dep; }t[maxn];
int T, n, m, cnt;
int root[maxn], c[maxn], dep[maxn], dfn[maxn], St[maxn], Ed[maxn], mp[maxn], head[maxn], to[maxn], nxt[maxn];
int f[maxn][20];

void dfs( int u ) {
	dep[u] = dep[f[u][0]] + 1;
	dfn[u] = St[u] = ++ cnt;
	mp[cnt] = u;
	for( int i = 1;i < 20;i ++ )
		f[u][i] = f[f[u][i - 1]][i - 1];
	for( int i = head[u];i;i = nxt[i] ) dfs( to[i] );
	Ed[u] = cnt;
}

struct Node { int lson, rson, sum; }tree[maxn * 50];

void modify( int &now, int lst, int l, int r, int pos, int k ) {
	tree[now = ++ cnt] = tree[lst];
	tree[now].sum += k;
	if( l == r ) return;
	int mid = ( l + r ) >> 1;
	if( pos <= mid ) modify( tree[now].lson, tree[lst].lson, l, mid, pos, k );
	else modify( tree[now].rson, tree[lst].rson, mid + 1, r, pos, k );
}

int query( int now, int l, int r, int L, int R ) {
	if( r < L or R < l ) return 0;
	if( L <= l and r <= R ) return tree[now].sum;
	int mid = ( l + r ) >> 1;
	return query( tree[now].lson, l, mid, L, R ) + query( tree[now].rson, mid + 1, r, L, R );
}

int lca( int u, int v ) {
	if( dep[u] < dep[v] ) swap( u, v );
	for( int i = 19;~ i;i -- ) if( dep[f[u][i]] >= dep[v] ) u = f[u][i];
	if( u == v ) return u;
	for( int i = 19;~ i;i -- ) if( f[u][i] ^ f[v][i] ) u = f[u][i], v = f[v][i];
	return f[u][0];
}

int main() {
	scanf( "%d", &T );
	while( T -- ) {
		scanf( "%d %d", &n, &m );
		for( int i = 1;i <= n;i ++ )	
			head[i] = 0, s[i].clear();
		for( int i = 1;i <= n;i ++ )	
			scanf( "%d", &c[i] );
		cnt = 1;
		for( int i = 2;i <= n;i ++ ) {
			scanf( "%d", &f[i][0] );
			to[cnt] = i, nxt[cnt] = head[f[i][0]], head[f[i][0]] = cnt ++;
		}
		cnt = 0;
		dfs( 1 );
		for( int i = 1;i <= n;i ++ )	
			t[i].id = i, t[i].dep = dep[i];
		sort( t + 1, t + n + 1, []( node x, node y ) { return x.dep < y.dep; } );
		cnt = 0;
		for( int i = 1;i <= n;i ++ ) {
			root[t[i].dep] = root[t[i - 1].dep];
			int id = t[i].id, d = t[i].dep;
			modify( root[d], root[d], 1, n, dfn[id], 1 );
			auto it = s[c[id]].lower_bound( dfn[id] );
			int pre = -1, nxt = -1;
			if( it != s[c[id]].end() ) {
				nxt = *it;
				modify( root[d], root[d], 1, n, dfn[lca( id, mp[nxt] )], -1 );
			}
			if( it != s[c[id]].begin() ) {
				pre = * (-- it);
				modify( root[d], root[d], 1, n, dfn[lca( id, mp[pre] )], -1 );
			}
			if( ~ pre and ~ nxt )
				modify( root[d], root[d], 1, n, dfn[lca( mp[pre], mp[nxt] )], 1 );
			s[c[id]].insert( dfn[id] );
		}
		int last = 0, x, d;
		while( m -- ) {
			scanf( "%d %d", &x, &d );
			x ^= last, d ^= last;
			printf( "%d\n", last = query( root[dep[x] + d], 1, n, St[x], Ed[x] ) );
		}
		cnt = 0;
	}
	return 0;
}

标签:int,lca,dep,dfn,maxn,4771,root
来源: https://blog.csdn.net/Emm_Titan/article/details/120293119

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

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

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

ICode9版权所有