【BZOJ4771】七彩树 主席树+树链的并
【BZOJ4771】七彩树
Description
Input
Output
Sample Input
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
2
3
1
1
2
1
1
题解:先不考虑深度的限制。我们分别考虑每种颜色。
如果这个颜色只有一个点,那么它对它的所有祖先的贡献都是1,如果有2个点a,b,那么它们对a和b的祖先贡献都是1,其中两者lca的祖先被重复计算了1次,要将它减去。
以此类推,这些点对它们的树链的并的贡献都是1,所以求出树链的并,用线段树维护子树权值和即可。
但是如果考虑深度限制呢?将线段树改成主席树即可,即对于每个深度都维护一棵线段树。
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <set>
using namespace std;
const int maxn=100010;
int n,m,cnt,tot,ans;
set<int> S[maxn];
set<int>::iterator it;
int to[maxn],next[maxn],head[maxn],fa[19][maxn],dep[maxn],Log[maxn],p[maxn],q[maxn],pd[maxn],Q[maxn],rt[maxn],v[maxn];
struct node
{
int ls,rs,siz;
}s[maxn*50];
void dfs(int x)
{
p[x]=++q[0],Q[q[0]]=x;
for(int i=head[x];i!=-1;i=next[i]) dep[to[i]]=dep[x]+1,dfs(to[i]);
q[x]=q[0];
}
inline int lca(int a,int b)
{
if(dep[a]<dep[b]) swap(a,b);
for(int i=Log[dep[a]-dep[b]];i>=0;i--) if(dep[fa[i][a]]>=dep[b]) a=fa[i][a];
if(a==b) return a;
for(int i=Log[dep[a]];i>=0;i--) if(fa[i][a]!=fa[i][b]) a=fa[i][a],b=fa[i][b];
return fa[0][a];
}
bool cmp(int a,int b)
{
return dep[a]<dep[b];
}
void insert(int x,int &y,int l,int r,int a,int b)
{
y=++tot,s[y].ls=s[y].rs=s[y].siz=0;
s[y].siz=s[x].siz+b;
if(l==r) return ;
int mid=(l+r)>>1;
if(a<=mid) s[y].rs=s[x].rs,insert(s[x].ls,s[y].ls,l,mid,a,b);
else s[y].ls=s[x].ls,insert(s[x].rs,s[y].rs,mid+1,r,a,b);
}
int query(int l,int r,int x,int a,int b)
{
if(!x||(a<=l&&r<=b)) return s[x].siz;
int mid=(l+r)>>1;
if(b<=mid) return query(l,mid,s[x].ls,a,b);
if(a>mid) return query(mid+1,r,s[x].rs,a,b);
return query(l,mid,s[x].ls,a,b)+query(mid+1,r,s[x].rs,a,b);
}
inline int rd()
{
int ret=0,f=1; char gc=getchar();
while(gc<'0'||gc>'9') {if(gc=='-') f=-f; gc=getchar();}
while(gc>='0'&&gc<='9') ret=ret*10+gc-'0',gc=getchar();
return ret*f;
}
inline void add(int a,int b)
{
to[cnt]=b,next[cnt]=head[a],head[a]=cnt++;
}
void work()
{
n=rd(),m=rd(),tot=cnt=ans=q[0]=0;
int i,j,a,b;
memset(head,-1,sizeof(head));
memset(rt,0,sizeof(rt));
memset(fa,0,sizeof(fa));
for(i=1;i<=n;i++) v[i]=rd(),S[i].clear(),pd[i]=i;
for(i=2;i<=n;i++) fa[0][i]=rd(),add(fa[0][i],i),Log[i]=Log[i>>1]+1;
dep[1]=1,dfs(1);
for(j=1;(1<<j)<=n;j++) for(i=1;i<=n;i++) fa[j][i]=fa[j-1][fa[j-1][i]];
sort(pd+1,pd+n+1,cmp);
for(i=1;i<=n;i++)
{
j=pd[i],a=b=0,it=S[v[j]].lower_bound(p[j]);
insert(rt[dep[pd[i-1]]],rt[dep[j]],1,n,p[j],1);
if(it!=S[v[j]].end()) b=Q[(*it)],insert(rt[dep[j]],rt[dep[j]],1,n,p[lca(b,j)],-1);
if(it!=S[v[j]].begin()) it--,a=Q[(*it)],insert(rt[dep[j]],rt[dep[j]],1,n,p[lca(a,j)],-1);
if(a&&b) insert(rt[dep[j]],rt[dep[j]],1,n,p[lca(a,b)],1);
S[v[j]].insert(p[j]);
}
for(i=1;i<=m;i++)
{
a=rd()^ans,b=rd()^ans;
ans=query(1,n,rt[min(dep[a]+b,dep[pd[n]])],p[a],q[a]);
printf("%d\n",ans);
//ans=0;
}
}
int main()
{
int T=rd();
while(T--) work();
return 0;
}//1 4 4 4 2 3 2 1 2 1 3 2 2 2 4 1 4 1
【BZOJ4771】七彩树 主席树+树链的并的更多相关文章
- dfs序+主席树 或者 树链剖分+主席树(没写) 或者 线段树套线段树 或者 线段树套splay 或者 线段树套树状数组 bzoj 4448
4448: [Scoi2015]情报传递 Time Limit: 20 Sec Memory Limit: 256 MBSubmit: 588 Solved: 308[Submit][Status ...
- VIJOS1107 求树的最长链
vijos1107环游大同80天 学习了一下求树的最长链的方法 最简单的思路就是两次dfs 两次dfs分别有什么用呢? 第一次dfs,求出某个任意的点能到达的最远的点 第二次dfs,从所搜到的最远的点 ...
- 线段树(单标记+离散化+扫描线+双标记)+zkw线段树+权值线段树+主席树及一些例题
“队列进出图上的方向 线段树区间修改求出总量 可持久留下的迹象 我们 俯身欣赏” ----<膜你抄> 线段树很早就会写了,但一直没有总结,所以偶尔重写又会懵逼,所以还是要总结一下. ...
- BZOJ_3589_动态树_容斥原理+树链剖分
BZOJ_3589_动态树_容斥原理+树链剖分 题意: 维护一棵树,支持1.子树内点权加上一个数 2.给出k条链,求路径上的点权和(重复的计算一次) (k<=5) 分析: 可以用树剖+线段树解 ...
- 树的最长链-POJ 1985 树的直径(最长链)+牛客小白月赛6-桃花
求树直径的方法在此转载一下大佬们的分析: 可以随便选择一个点开始进行bfs或者dfs,从而找到离该点最远的那个点(可以证明,离树上任意一点最远的点一定是树的某条直径的两端点之一:树的直径:树上的最长简 ...
- [BZOJ4539][HNOI2016]树(主席树)
4539: [Hnoi2016]树 Time Limit: 40 Sec Memory Limit: 256 MBSubmit: 746 Solved: 292[Submit][Status][D ...
- 小结:线段树 & 主席树 & 树状数组
概要: 就是用来维护区间信息,然后各种秀智商游戏. 技巧及注意: 一定要注意标记的下放的顺序及影响!考虑是否有叠加或相互影响的可能! 和平衡树相同,在操作每一个节点时,必须保证祖先的tag已经完全下放 ...
- 线段树简单入门 (含普通线段树, zkw线段树, 主席树)
线段树简单入门 递归版线段树 线段树的定义 线段树, 顾名思义, 就是每个节点表示一个区间. 线段树通常维护一些区间的值, 例如区间和. 比如, 上图 \([2, 5]\) 区间的和, 为以下区间的和 ...
- 2016湖南省赛 I Tree Intersection(线段树合并,树链剖分)
2016湖南省赛 I Tree Intersection(线段树合并,树链剖分) 传送门:https://ac.nowcoder.com/acm/contest/1112/I 题意: 给你一个n个结点 ...
- 权值线段树&&可持久化线段树&&主席树
权值线段树 顾名思义,就是以权值为下标建立的线段树. 现在让我们来考虑考虑上面那句话的产生的三个小问题: 1. 如果说权值作为下标了,那这颗线段树里存什么呢? ----- 这颗线段树中, 记录每个值出 ...
随机推荐
- 使用Visual Studio的动态连接库创建通用数据库连接对话框
1.在VS(此处文件夹文件以vs2010为例)安装文件夹下("%Visual Studio安装文件夹%/Common10/IDE/Microsoft.Data.ConnectionUI.Di ...
- Crontab命令--Linux
Crontab命令--定时任务 命令格式 Example:
- 原生js 操作类名
添加类名: document.getElementById('navBar').getElementsByClassName('mui-tab-item')[0].classList.add('mui ...
- iOS 之UIBezierPath
代码地址如下:http://www.demodashi.com/demo/11602.html 在之前的文章中,由于用到过UIBezierPath这个类,所以这里就对这个类进行简单的记录一下,方便自己 ...
- hiredis中异步的实现小结
hiredis中异步的实现小结 原文: http://blog.csdn.net/l1902090/article/details/3858... 时间: 2014-08-15 前言 一般情况下我们使 ...
- EntityFramework.SqlServer.dll 中发生 其他信息: 在与 SQL Server 建立连接时出现与网络相关的或特定于实例的错误。未找到或无法访问服务器。请验证实例名称是否正确并且 SQL Server 已配置为允许远程连接。 (provider: Named Pipes Provider, error: 40 - 无法打开到 SQL Server 的连接)
解决方案: 1.打开Sql server 管理配置器 或者在命令行输入:SQLServerManager10.msc 2.点击MSSQLSERVER的协议,在右侧的页面中选择TCP/IP协议启用 3. ...
- Centos下安装JDK、Maven和Git
原文地址:https://github.com/eacdy/spring-cloud-book/blob/master/3%20%E4%BD%BF%E7%94%A8Docker%E6%9E%84%E5 ...
- nginx跨域(转2)
当出现403跨域错误的时候 No 'Access-Control-Allow-Origin' header is present on the requested resource,需要给Nginx服 ...
- 采用CDN加速后,如何在程序里获取用户IP地址
现在很多网站用了CDN技术,但采用CDN技术后,原来用来获取访问源的IP地址的程序已不能正常使用,它拿到的并不是访问源的真实IP地址,而是CDN节点的IP地址,解决方法是对获取IP的代码作一点小改动. ...
- arm linux c++11编译
include(CheckCXXCompilerFlag) CHECK_CXX_COMPILER_FLAG("-std=c++11" COMPILER_SUPPORTS_CXX11 ...