考虑没有深度限制怎么做。显然的做法是直接转成dfs序上主席树,但如果拓展到二维变成矩形数颜色数肯定没法做到一个log。

  另一种做法是利用树上差分。对于同种颜色的点,在每个点处+1,dfs序相邻点的lca处-1,那么查询子树颜色数就只需要查询子树和了。

  然后加上深度限制。考虑将点一层层加进去,利用set查找dfs序中前驱后继同色点,对dfs序建线段树实现动态树上差分。于是再对深度建主席树就可以在线回答询问了。

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<vector>
#include<set>
using namespace std;
#define ll long long
#define N 100010
char getc(){char c=getchar();while ((c<'A'||c>'Z')&&(c<'a'||c>'z')&&(c<''||c>'')) c=getchar();return c;}
int gcd(int n,int m){return m==?n:gcd(m,n%m);}
int read()
{
int x=,f=;char c=getchar();
while (c<''||c>'') {if (c=='-') f=-;c=getchar();}
while (c>=''&&c<='') x=(x<<)+(x<<)+(c^),c=getchar();
return x*f;
}
int T,n,m,color[N],deep[N],size[N],fa[N][],p[N],dfn[N],id[N],root[N],t,cnt,lastans;
vector<int> a[N];
set<int> c[N];
struct data{int to,nxt;
}edge[N<<];
struct data2{int l,r,x;
}tree[N<<];
void addedge(int x,int y){t++;edge[t].to=y,edge[t].nxt=p[x],p[x]=t;}
void dfs(int k)
{
dfn[k]=++cnt,id[cnt]=k,size[k]=;a[deep[k]].push_back(k);
for (int i=p[k];i;i=edge[i].nxt)
if (edge[i].to!=fa[k][])
{
deep[edge[i].to]=deep[k]+;
dfs(edge[i].to);
size[k]+=size[edge[i].to];
}
}
int lca(int x,int y)
{
if (deep[x]<deep[y]) swap(x,y);
for (int j=;~j;j--) if (deep[fa[x][j]]>=deep[y]) x=fa[x][j];
if (x==y) return x;
for (int j=;~j;j--) if (fa[x][j]!=fa[y][j]) x=fa[x][j],y=fa[y][j];
return fa[x][];
}
void add(int &k,int l,int r,int p,int x)
{
tree[++cnt]=tree[k],k=cnt;tree[k].x+=x;
if (l==r) return;
int mid=l+r>>;
if (p<=mid) add(tree[k].l,l,mid,p,x);
else add(tree[k].r,mid+,r,p,x);
}
int query(int x,int y,int L,int R,int l,int r)
{
if (!y) return ;
if (L==l&&R==r) return tree[y].x-tree[x].x;
int mid=L+R>>;
if (r<=mid) return query(tree[x].l,tree[y].l,L,mid,l,r);
else if (l>mid) return query(tree[x].r,tree[y].r,mid+,R,l,r);
else return query(tree[x].l,tree[y].l,L,mid,l,mid)+query(tree[x].r,tree[y].r,mid+,R,mid+,r);
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("bzoj4771.in","r",stdin);
freopen("bzoj4771.out","w",stdout);
const char LL[]="%I64d\n";
#else
const char LL[]="%lld\n";
#endif
T=read();
while (T--)
{
n=read(),m=read();
for (int i=;i<=n;i++) color[i]=read();
memset(p,,sizeof(p)),t=;
for (int i=;i<=n;i++) addedge(fa[i][]=read(),i);
fa[][]=;deep[]=;cnt=;
for (int i=;i<=n;i++) a[i].clear(),c[color[i]].clear();
dfs();
for (int j=;j<;j++)
for (int i=;i<=n;i++)
fa[i][j]=fa[fa[i][j-]][j-];
root[]=cnt=;
for (int i=;i<=n;i++)
{
root[i]=root[i-];
for (int j=;j<a[i].size();j++)
{
int x=a[i][j];
add(root[i],,n,dfn[x],);
c[color[x]].insert(dfn[x]);
set<int>::iterator it=c[color[x]].find(dfn[x]);
int pre=,suf=;
it++;if (it!=c[color[x]].end()) suf=*it;it--;
if (it!=c[color[x]].begin()) it--,pre=*it;
if (pre&&suf) add(root[i],,n,dfn[lca(id[pre],id[suf])],);
if (pre) add(root[i],,n,dfn[lca(id[pre],x)],-);
if (suf) add(root[i],,n,dfn[lca(id[suf],x)],-);
}
}
lastans=;
while (m--)
{
int x=read()^lastans,d=read()^lastans;
printf("%d\n",lastans=query(root[deep[x]-],root[deep[x]+d],,n,dfn[x],dfn[x]+size[x]-));
}
}
return ;
}

BZOJ4771 七彩树(dfs序+树上差分+主席树)的更多相关文章

  1. BZOJ4999:This Problem Is Too Simple!(DFS序&树上差分&线段树动态开点:区间修改单点查询)

    Description 给您一颗树,每个节点有个初始值. 现在支持以下两种操作: 1. C i x(0<=x<2^31) 表示将i节点的值改为x. 2. Q i j x(0<=x&l ...

  2. BZOJ 3551/3545: [ONTAK2010]Peaks加强版 (Kruskal树+dfs序上的主席树+倍增)

    Orz PoPoQQQ 学到了维护子树信息的时候用dfsdfsdfs序套主席树节省线段树空间. 学到了怎么用指针写可持久化线段树-emmm- CODE 只贴上3551加强版带强制在线的代码 #incl ...

  3. 【BZOJ-1146】网络管理Network DFS序 + 带修主席树

    1146: [CTSC2008]网络管理Network Time Limit: 50 Sec  Memory Limit: 162 MBSubmit: 3495  Solved: 1032[Submi ...

  4. BZOJ3545&3551[ONTAK2010]Peaks——kruskal重构树+主席树+dfs序+树上倍增

    题目描述 在Bytemountains有N座山峰,每座山峰有他的高度h_i.有些山峰之间有双向道路相连,共M条路径,每条路径有一个困难值,这个值越大表示越难走,现在有Q组询问,每组询问询问从点v开始只 ...

  5. bzoj 3551 kruskal重构树dfs序上的主席树

    强制在线 kruskal重构树,每两点间的最大边权即为其lca的点权. 倍增找,dfs序对应区间搞主席树 #include<cstdio> #include<cstring> ...

  6. 洛谷2414(构建ac自动机fail树dfs序后遍历Trie树维护bit及询问答案)

    要点 这是一道蔡队题,看我标题行事 任意询问y串上有多少个x串,暴力找每个节点是不是结尾肯定是炸的,考虑本质:如果某节点是x的结尾,根据ac自动机的性质,x一定是此(子)串后缀.又有每个Trie节点的 ...

  7. bzoj 3307: 雨天的尾巴【树剖lca+树上差分+线段树合并】

    这居然是我第一次写线段树合并--所以我居然在合并的时候加点结果WAWAWAMLEMLEMLE--!ro的时候居然直接指到la就行-- 树上差分,每个点建一棵动态开点线段树,然后统计答案的时候合并即可 ...

  8. P4556 [Vani有约会]雨天的尾巴 /【模板】线段树合并 (树上差分+线段树合并)

    显然的树上差分问题,最后要我们求每个点数量最多的物品,考虑对每个点建议线段树,查询子树时将线段树合并可以得到答案. 用动态开点的方式建立线段树,注意离散化. 1 #include<bits/st ...

  9. 【bzoj4771】七彩树 树链的并+STL-set+DFS序+可持久化线段树

    题目描述 给定一棵n个点的有根树,编号依次为1到n,其中1号点是根节点.每个节点都被染上了某一种颜色,其中第i个节点的颜色为c[i].如果c[i]=c[j],那么我们认为点i和点j拥有相同的颜色.定义 ...

随机推荐

  1. 20145234黄斐《信息安全系统设计基础》第六周学习总结(Y86模拟器的安装)

    Y86模拟器的安装 由于本人的电脑有些问题,在安装的时候忽然断电导致之前的成果都没有截图. 1.安装bison和flex词法分析工具 sudo apt-get install bison flex t ...

  2. BZOJ1222_ 产品加工_KEY

    题目传送门 我们设f[i]表示用机器A加工,时间还剩下i时的最优加工时间. 对于每一个时间可以加工的物品,有以下几个选择: 1.用机器A加工 2.用机器B加工 3.A和B一起加工 所以得到方程: f[ ...

  3. 【CF613D】Kingdom and its Cities(虚树,动态规划)

    [CF613D]Kingdom and its Cities(虚树,动态规划) 题面 洛谷 CF 翻译洛谷上有啦 题解 每次构建虚树,首先特判无解,也就是关键点中存在父子关系. 考虑\(dp\),设\ ...

  4. LeetCode:43. Multiply Strings (Medium)

    1. 原题链接 https://leetcode.com/problems/multiply-strings/description/ 2. 题目要求 给定两个String类型的正整数num1.num ...

  5. CLR via c#读书笔记五:方法

    注:书本第8章:方法 实例构造器和类(引用类型) 构造器方法在“方法定义元数据表”中始终叫做.ctor(constructor的简称). 构造引用类型的对象,在调用类型的实例构造器之前,为对象分配的内 ...

  6. Calendar 实现日历实例

    import java.text.ParseException; import java.util.Calendar; import java.util.GregorianCalendar; impo ...

  7. Qt-序列号生成器

    一直想做一个序列号的生成器,今天终于有了开始了,目前只有读取硬件生成,还没有做生成序列号的规则. 目前实现的功能就是读取系统磁盘卷加上CPU ID 和自己的加密字符串,在利用MD5加密,转换成标准32 ...

  8. Git命令使用大全

    一前言 最近公司在使用vue和WebAPI前后端分离的项目开发,使用的代码管理工具是git,刚开始使用的时候前端的vue文件还比较好处理,但是后端的C#文件在每一次自己编译之后上传都会和其他小伙伴的代 ...

  9. python 中的reload(sys)

    import sys  reload(sys)  sys.setdefaultencoding('utf-8') #python2中的使用方法 #重新载入 sys 模块,并设置默认编码为 utf8 & ...

  10. 【转】从零开始学习Skynet_examples研究

    转自 http://blog.csdn.net/mr_virus/article/details/52330193 一.编译Skynet: 1.用ubuntu15.10直接 make linux 编译 ...