BZOj #4771. 七彩树

  • description
  • solution
  • code

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序,然后就可以用线段树维护,变成区间问题

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

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

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

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

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

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

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

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

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

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

但是前驱和后继的lca又多减了111,所以要对其进行+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;
}

BZOj #4771. 七彩树(主席树+dfn序+lca)相关推荐

  1. 线段树简单入门 (含普通线段树, zkw线段树, 主席树)

    线段树简单入门 递归版线段树 线段树的定义 线段树, 顾名思义, 就是每个节点表示一个区间. 线段树通常维护一些区间的值, 例如区间和. 比如, 上图 \([2, 5]\) 区间的和, 为以下区间的和 ...

  2. bzoj 4012: [HNOI2015]开店 主席树

    Description 风见幽香有一个好朋友叫八云紫,她们经常一起看星星看月亮从诗词歌赋谈到 人生哲学.最近她们灵机一动,打算在幻想乡开一家小店来做生意赚点钱.这样的 想法当然非常好啦,但是她们也发现 ...

  3. 【BZOJ4771】七彩树 主席树+树链的并

    [BZOJ4771]七彩树 Description 给定一棵n个点的有根树,编号依次为1到n,其中1号点是根节点.每个节点都被染上了某一种颜色,其中第i个节点的颜色为c[i].如果c[i]=c[j], ...

  4. 2021HDU多校10 - 7084 Pty loves string(KMPnext树+主席树+dfs序)

    题目链接:点击查看 题目大意:给出一个长度为 nnn 的字符串 sss,需要回答 qqq 次询问,每次询问给出一对 (x,y)(x,y)(x,y) ,意思是用 sss 的前缀 s[1:x]s[1:x] ...

  5. BZOJ.3524.[POI2014]Couriers(主席树)

    题目链接 //119964kb 5780ms //主席树裸题啊.. #include <cstdio> #include <cctype> #define gc() getch ...

  6. Governing sand(权值线段树/主席树)

    链接:https://ac.nowcoder.com/acm/contest/887/C 来源:牛客网 时间限制:C/C++ 3秒,其他语言6秒 空间限制:C/C++ 65536K,其他语言13107 ...

  7. HDU - 7084 Pty loves string kmp + fail树 + 主席树

    传送门 文章目录 题意: 思路: 题意: 给你一个字符串sss,有qqq个询问,每次给x,yx,yx,y代表取sss的前xxx个字符和后yyy个字符拼接起来得到ttt,输出ttt在sss中出现的次数. ...

  8. 可持久化线段树——主席树

    前言: 最近心(po)血(yu)来(ya)潮(li)学习了一下主席树.(再不学就落伍了) 主席树,即可持久化线段树,支持维护和查询区间的第\(k\)大(小).区间不同种类个数等,基于线段树的思想之上 ...

  9. 牛客网 暑期ACM多校训练营(第一场)J.Different Integers-区间两侧不同数字的个数-离线树状数组 or 可持久化线段树(主席树)...

    J.Different Integers 题意就是给你l,r,问你在区间两侧的[1,l]和[r,n]中,不同数的个数. 两种思路: 1.将数组长度扩大两倍,for(int i=n+1;i<=2* ...

最新文章

  1. BZOJ4539: [Hnoi2016]树
  2. 【Java】7.1 与用户互动 7.2 系统相关
  3. 第九天学习Java的笔记(方法重载)
  4. Linux执行shell脚本的四种方式
  5. 【题解】lugu P4095 Eden的新背包问题
  6. Spark基本操作SparkSession,DatasetRow,JavaRDDRow
  7. 云服务器 生物信息学,云服务器 生物信息学
  8. 利用python获取nginx服务的ip以及流量统计信息
  9. PuTTYgen 使用
  10. plsql导出单表数据
  11. MEMS传感市场,美/日/德企占主导地位
  12. selenium模拟登录某宝
  13. python判断是否为整数的函数_实现函数 isInteger(x) 来判断 x 是否是整数
  14. python+大数据-MySQL-day02(黑马)
  15. TCP应用层主要协议
  16. 打印服务spoolsv.exe应用程序错误解决方法
  17. 【51单片机】延时函数计算问题以及如何准确延时
  18. iOS即时语音聊天技术实践
  19. win10网络邻居看到linux,win10网络邻居找不到其他电脑怎么办
  20. abp生成proxy代理时的一些问题记录

热门文章

  1. 算法有偏见?总比人类识别强吧!
  2. PPT快捷键大全(作分析报告的人有福了)
  3. 三次握手和四次挥手图解_三次握手和四次挥手简单理解
  4. dialog element 删掉标题_ElementUI 销毁Dialog数据(简单粗暴)
  5. oracle crontab e,Linux运维知识之通过crontab -e编辑生成的定时任务,写在哪个文件中...
  6. 和flag_不怕立Flag,就怕没有Flag
  7. anaconda和python有什么不一样_黄山毛峰的味道为什么会不一样?
  8. 用python画树_Python+Turtle动态绘制一棵树实例分享
  9. 乐视android版本点四下,EUI5.9+Android7.0刷机包
  10. 算法设计与分析——递归与分治策略——全排列