https://blog.csdn.net/KsCla/article/details/78249148

用类似经典的链上区间颜色计数问题的做法,这个题可以看成是询问DFS在[L[x],R[x]]中,深度在[dep[x],dep[x]+d]中,上一个同色点在[0,L[x]-1]中的点的个数。这是个三维数点问题,如果不强制在线的话,可以离线解决一维,主席树解决两维。

强制在线的话,其实还有一个“离线”方法:在所有询问前就将所有答案全部算好。

考虑两个同色点,在不考虑深度的情况下,它们所贡献的点是它们到根的链的并。对于链并问题,往往用set维护dfs序,然后插入点时处理dfs序相邻的两项的信息(差分),可以通过线段树来支持动态差分。

现在考虑深度,按深度建主席树即可。

讲的并不清楚,具体还是看上面的题解吧。代码应该还是比较好理解的。

 #include<set>
#include<cstdio>
#include<vector>
#include<algorithm>
#define rep(i,l,r) for (int i=(l); i<=(r); i++)
#define For(i,x) for (int i=h[x],k; i; i=nxt[i])
typedef long long ll;
using namespace std; const int N=,M=;
int T,n,m,u,v,cnt,ans,tim,nd,x,d,co[N],dep[N],h[N],to[N],nxt[N];
int ls[M],rs[M],sm[M],fa[N][],L[N],R[N],pos[N],rt[N];
vector<int>a[N];
set<int>c[N]; void add(int u,int v){ to[++cnt]=v; nxt[cnt]=h[u]; h[u]=cnt; } void dfs(int x){
rep(i,,) fa[x][i]=fa[fa[x][i-]][i-];
dep[x]=dep[fa[x][]]+; L[x]=++tim;
pos[tim]=x; a[dep[x]].push_back(x);
For(i,x) dfs(k=to[i]); R[x]=tim;
} int lca(int u,int v){
if (dep[u]<dep[v]) swap(u,v);
int t=dep[u]-dep[v];
for (int i=; ~i; i--) if (t&(<<i)) u=fa[u][i];
if (u==v) return u;
for (int i=; ~i; i--) if (fa[u][i]!=fa[v][i]) u=fa[u][i],v=fa[v][i];
return fa[u][];
} void ins(int &x,int y,int L,int R,int pos,int k){
x=++nd; ls[x]=ls[y]; rs[x]=rs[y]; sm[x]=sm[y]+k;
if (L==R) return;
int mid=(L+R)>>;
if (pos<=mid) ins(ls[x],ls[y],L,mid,pos,k);
else ins(rs[x],rs[y],mid+,R,pos,k);
} int que(int x,int y,int L,int R,int l,int r){
if (!y) return ;
if (L==l && r==R) return sm[y]-sm[x];
int mid=(L+R)>>;
if (r<=mid) return que(ls[x],ls[y],L,mid,l,r);
else if (l>mid) return que(rs[x],rs[y],mid+,R,l,r);
else return que(ls[x],ls[y],L,mid,l,mid)+que(rs[x],rs[y],mid+,R,mid+,r);
} int main(){
freopen("bzoj4771.in","r",stdin);
freopen("bzoj4771.out","w",stdout);
for (scanf("%d",&T); T--; ){
scanf("%d%d",&n,&m);
rep(i,,n) h[i]=; cnt=tim=ans=nd=;
rep(i,,n) scanf("%d",&co[i]);
rep(i,,n) scanf("%d",&fa[i][]),add(fa[i][],i);
rep(i,,n) a[i].clear(),c[co[i]].clear();
dfs();
rep(i,,n){
rt[i]=rt[i-]; int ed=a[i].size()-;
rep(j,,ed){
int x=a[i][j]; ins(rt[i],rt[i],,n,L[x],); c[co[x]].insert(L[x]);
set<int>::iterator it=c[co[x]].find(L[x]);
int pre=,suf=; it++;
if (it!=c[co[x]].end()) suf=*it; it--;
if (it!=c[co[x]].begin()) it--,pre=*it;
if (pre && suf) ins(rt[i],rt[i],,n,L[lca(pos[pre],pos[suf])],);
if (pre) ins(rt[i],rt[i],,n,L[lca(pos[pre],x)],-);
if (suf) ins(rt[i],rt[i],,n,L[lca(pos[suf],x)],-);
}
}
while (m--){
scanf("%d%d",&x,&d); x^=ans; d^=ans;
printf("%d\n",ans=que(rt[dep[x]-],rt[dep[x]+d],,n,L[x],R[x]));
}
}
return ;
}

[BZOJ4771]七彩树(主席树)的更多相关文章

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

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

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

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

  3. 【BZOJ3439】Kpm的MC密码 trie树+主席树

    Description 背景 想Kpm当年为了防止别人随便进入他的MC,给他的PC设了各种奇怪的密码和验证问题(不要问我他是怎么设的...),于是乎,他现在理所当然地忘记了密码,只能来解答那些神奇的身 ...

  4. 学习笔记--函数式线段树(主席树)(动态维护第K极值(树状数组套主席树))

    函数式线段树..资瓷 区间第K极值查询 似乎不过似乎划分树的效率更优于它,但是如果主席树套树状数组后,可以处理动态的第K极值.即资瓷插入删除,划分树则不同- 那么原理也比较易懂: 建造一棵线段树(权值 ...

  5. HDU5790 Prefix 字典树+主席树

    分析:这个题和spoj的d_query是一个题,那个是求一段区间里有多少个不同的数字,这里是统计有多少个不同的前缀 用字典树进行判重,(和查询不同的数字一样)对于每个不同的前缀,只保留它最后一次出现的 ...

  6. bzoj 3545&&3551: [ONTAK2010]Peaks &&加强版 平衡树&&并查集合并树&&主席树

    3545: [ONTAK2010]Peaks Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 635  Solved: 177[Submit][Stat ...

  7. BZOJ 4539: [Hnoi2016]树 [主席树 lca]

    4539: [Hnoi2016]树 题意:不想写.复制模板树的子树,查询两点间距离. *** 终于有一道会做的题了...... 画一画发现可以把每次复制的子树看成一个大点来建一棵树,两点的lca一定在 ...

  8. 线段树(单标记+离散化+扫描线+双标记)+zkw线段树+权值线段树+主席树及一些例题

    “队列进出图上的方向 线段树区间修改求出总量 可持久留下的迹象 我们 俯身欣赏” ----<膜你抄>     线段树很早就会写了,但一直没有总结,所以偶尔重写又会懵逼,所以还是要总结一下. ...

  9. UOJ#218. 【UNR #1】火车管理 线段树 主席树

    原文链接https://www.cnblogs.com/zhouzhendong/p/UOJ218.html 题解 如果我们可以知道每次弹出栈之后新的栈顶是什么,那么我们就可以在一棵区间覆盖.区间求和 ...

随机推荐

  1. Windows无法访问局域网内共享文件夹[0x800704cf,0x80070035]解决方案

    Windows7系统突然无法访问访问其他windows机器的共享文件夹,出现0x800704cf或者0x80070035错误: 解决方案如下两张图,配置与下面两张图为准,即可解决: 1:window+ ...

  2. node.js、git、bootstrap等安装配置

    纯记录 一,安装node.js 1 官方网址 http://nodejs.org/  点击install 下载node-v0.10.22-x86.msi 2 安装,修改安装目录到d盘,一路next,无 ...

  3. 深拷贝数组 np.copy

    数组对象自带了浅拷贝和深拷贝的方法,但是一般用深拷贝多一些: 代码如下: >>> a = np.ones((2,2)) >>> b = a >>> ...

  4. ubuntu git 简单入门【转】

    转自:http://blog.chinaunix.net/uid-20718384-id-3334859.html 1. 安装 sudo apt-get install git-core 2.  初始 ...

  5. select()函数用法二

    Select在Socket编程中还是比较重要的,可是对于初学Socket的人来说都不太爱用Select写程序,他们只是习惯写诸如 connect.accept.recv或recvfrom这样的阻塞程序 ...

  6. Java 并发--线程创建

    随着处理器的多核化,为提高处理器的资源利用率应用程序的并发变应运而生了.现在的操作系统是多任务操作系统,多线程是实现多任务的一种方式. 进程是指一个内存中运行的应用程序,每个进程都有自己独立的内存空间 ...

  7. js实现数据视图双向绑定原理

    这个方法了不起啊..vue.js和avalon.js 都是通过它实现双向绑定的..而且Object.observe也被草案发起人撤回了..所以defineProperty更有必要了解一下了几行代码看他 ...

  8. ArcMap2SLD使用

    1.首先打开ArcMap,加载一副mxd地图: 2.打开ArcGIS2SLD,如下图所示: 3.选择样式文件的保存形式,一副mxd地图可能有多个图层,选中In Separate Dateien/In ...

  9. 在虚拟机(vmware)上安装CentOS

    第一步是安装虚拟机,这个比较简单就不讲了. 第二步准备CentOS的镜像文件准备安装 第三步安装CentOS: 新建虚拟机 选择自定义配置 选择硬件兼容标准 选择是否让vmware安装操作系统 选择将 ...

  10. 监听 手机back键和顶部的回退

    // 回退事件,监听 手机back键和顶部的回退 pushHistory(); window.addEventListener("popstate", function(e) { ...