BZOJ4771 七彩树(dfs序+树上差分+主席树)
考虑没有深度限制怎么做。显然的做法是直接转成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序+树上差分+主席树)的更多相关文章
- 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 ...
- BZOJ 3551/3545: [ONTAK2010]Peaks加强版 (Kruskal树+dfs序上的主席树+倍增)
Orz PoPoQQQ 学到了维护子树信息的时候用dfsdfsdfs序套主席树节省线段树空间. 学到了怎么用指针写可持久化线段树-emmm- CODE 只贴上3551加强版带强制在线的代码 #incl ...
- 【BZOJ-1146】网络管理Network DFS序 + 带修主席树
1146: [CTSC2008]网络管理Network Time Limit: 50 Sec Memory Limit: 162 MBSubmit: 3495 Solved: 1032[Submi ...
- BZOJ3545&3551[ONTAK2010]Peaks——kruskal重构树+主席树+dfs序+树上倍增
题目描述 在Bytemountains有N座山峰,每座山峰有他的高度h_i.有些山峰之间有双向道路相连,共M条路径,每条路径有一个困难值,这个值越大表示越难走,现在有Q组询问,每组询问询问从点v开始只 ...
- bzoj 3551 kruskal重构树dfs序上的主席树
强制在线 kruskal重构树,每两点间的最大边权即为其lca的点权. 倍增找,dfs序对应区间搞主席树 #include<cstdio> #include<cstring> ...
- 洛谷2414(构建ac自动机fail树dfs序后遍历Trie树维护bit及询问答案)
要点 这是一道蔡队题,看我标题行事 任意询问y串上有多少个x串,暴力找每个节点是不是结尾肯定是炸的,考虑本质:如果某节点是x的结尾,根据ac自动机的性质,x一定是此(子)串后缀.又有每个Trie节点的 ...
- bzoj 3307: 雨天的尾巴【树剖lca+树上差分+线段树合并】
这居然是我第一次写线段树合并--所以我居然在合并的时候加点结果WAWAWAMLEMLEMLE--!ro的时候居然直接指到la就行-- 树上差分,每个点建一棵动态开点线段树,然后统计答案的时候合并即可 ...
- P4556 [Vani有约会]雨天的尾巴 /【模板】线段树合并 (树上差分+线段树合并)
显然的树上差分问题,最后要我们求每个点数量最多的物品,考虑对每个点建议线段树,查询子树时将线段树合并可以得到答案. 用动态开点的方式建立线段树,注意离散化. 1 #include<bits/st ...
- 【bzoj4771】七彩树 树链的并+STL-set+DFS序+可持久化线段树
题目描述 给定一棵n个点的有根树,编号依次为1到n,其中1号点是根节点.每个节点都被染上了某一种颜色,其中第i个节点的颜色为c[i].如果c[i]=c[j],那么我们认为点i和点j拥有相同的颜色.定义 ...
随机推荐
- Java面向对象之抽象方法&接口
在开始写抽象类之前,有一个问题我觉得想清楚会对理解抽象类很有帮助:那就是为什么要设计抽象类? 难道用类还不够么,为什么要设计出抽象类这样一个东西.我们可以换个角度来理解,就是有些类本来就是不应该被实例 ...
- 北京Uber优步司机奖励政策(3月12日~3月13日)
滴快车单单2.5倍,注册地址:http://www.udache.com/ 如何注册Uber司机(全国版最新最详细注册流程)/月入2万/不用抢单:http://www.cnblogs.com/mfry ...
- 如何用istio实现应用的灰度发布
Istio为用户提供基于微服务的流量治理能力.Istio允许用户按照标准制定一套流量分发规则,并且无侵入的下发到实例中,平滑稳定的实现灰度发布功能. 基于华为云的Istio服务网格技术,使得灰度发布全 ...
- 「题目代码」P1060~P1065(Java)
P1060 谭浩强C语言(第三版)习题7.5 注意行末空格. import java.util.*; import java.io.*; import java.math.*; import java ...
- 180606-Linux下jdk中文乱码问题解决
文章链接:https://liuyueyi.github.io/hexblog/2018/06/06/180606-Linux下jdk中文乱码问题解决/ linux下jdk中文乱码问题解决 之前遇到过 ...
- FU-A方式分包
当 NALU 的长度超过 MTU 时, 就必须对 NALU 单元进行分片封包. 也称为 Fragmentation Units (FUs). 0 1 2 3 0 1 2 3 4 5 6 7 8 9 ...
- Python教程:Python中的for 语句
Python 中的 for 语句与你在 C 或 Pascal 中可能用到的有所不同. Python教程 中的 for 语句并不总是对算术递增的数值进行迭代(如同 Pascal),或是给予用户定义迭代步 ...
- 【WXS全局对象】JSON
方法: 原型:JSON.stringify( Object ) 说明:将 object 对象转换为 JSON 字符串,并返回该字符串. 返回:[String] 原型:JSON.parse( [Stri ...
- lintcode: Check Sum of Square Numbers
Check Sum of Square Numbers Given a integer c, your task is to decide whether there're two integers ...
- 统计学习三:1.k近邻法
全文引用自<统计学习方法>(李航) K近邻算法(k-nearest neighbor, KNN) 是一种非常简单直观的基本分类和回归方法,于1968年由Cover和Hart提出.在本文中, ...