BZOJ.4771.七彩树(可持久化线段树)
考虑没有深度限制,对整棵子树询问怎么做。
对于同种颜色中DFS序相邻的两个点\(u,v\),在\(dfn[u],dfn[v]\)处分别\(+1\),\(dfn[LCA(u,v)]\)处\(-1\),这样答案就是求子树和了(同种颜色多余贡献的会被减掉)。
对于深度的限制,考虑维护\(\max\{dep\}\)棵线段树\(T_i\),分别表示只考虑深度在\(1\sim i\)之间的点的贡献(下标依旧是DFS序)。因为我们发现,对于询问\((x,k)\),求\(T_{dep[x]+k}\)这棵线段树中(也就是只考虑深度在\(1\sim dep[x]+k\)的点),区间\([dfn[x],ed\_dfn[x]]\)的和,就是答案。因为可能的问题是会统计到区间中深度\(<dep[x]\)的点,但是区间\([dfn[x],ed\_dfn[x]]\)中没有深度\(<dep[x]\)的点啊!
所以我们按深度维护出可持久化线段树就OK了。
对于深度由\(d-1\)变成\(d\),考虑在\(T_d\)中深度为\(d\)的点\(x\)的贡献。
同样像最初提到的那样,找出与\(x\)颜色相同且DFS序相邻的两个点\(pre,nxt\),把\(LCA(pre,nxt)\)的\(-1\)加回去,再减掉\(LCA(pre,x),LCA(x,nxt)\)的贡献即可(当然这两个LCA中有一个就是\(LCA(pre,nxt)\))。对每种颜色用\(set\)维护一下前驱后继。
复杂度\(O(n\log n)\)。
注意下\(dep[x]+k\)对\(\max\{dep\}\)取\(\min\)。
感觉代码也没有那么难写啊
//57056kb 1440ms
#include <set>
#include <cstdio>
#include <cctype>
#include <vector>
#include <cstring>
#include <algorithm>
#define gc() getchar()
#define MAXIN 300000
//#define gc() (SS==TT&&(TT=(SS=IN)+fread(IN,1,MAXIN,stdin),SS==TT)?EOF:*SS++)
typedef long long LL;
const int N=1e5+5;
int col[N],root[N],H[N],nxt[N],dep[N],fa[N],sz[N],son[N],top[N],Index,dfn[N],ref[N],R[N];
std::set<int> st[N];
std::vector<int> vec[N];
char IN[MAXIN],*SS=IN,*TT=IN;
struct Segment_Tree
{
#define ls son[x][0]
#define rs son[x][1]
#define lson ls,l,m
#define rson rs,m+1,r
#define S N*37//2logn!
int tot,sum[S],son[S][2];
#undef S
void Modify(int &x,int y,int l,int r,int p,int v)
{
x=++tot, sum[x]=sum[y]+v;
if(l==r) {ls=rs=0; return;}
int m=l+r>>1;
p<=m ? (rs=son[y][1],Modify(ls,son[y][0],l,m,p,v)) : (ls=son[y][0],Modify(rs,son[y][1],m+1,r,p,v));
}
int Query(int x,int l,int r,int L,int R)
{
if(!x) return 0;
if(L<=l && r<=R) return sum[x];
int m=l+r>>1;
if(L<=m)
if(m<R) return Query(lson,L,R)+Query(rson,L,R);
else return Query(lson,L,R);
return Query(rson,L,R);
}
}T;
inline int read()
{
int now=0;register char c=gc();
for(;!isdigit(c);c=gc());
for(;isdigit(c);now=now*10+c-48,c=gc());
return now;
}
inline void AE(int u,int v)
{
nxt[v]=H[u], H[u]=v;
}
inline int LCA(int u,int v)
{
if(u==-1||v==-1) return -1;
while(top[u]!=top[v]) dep[top[u]]>dep[top[v]]?u=fa[top[u]]:v=fa[top[v]];
return dep[u]>dep[v]?v:u;
}
void DFS1(int x)
{
int mx=0; sz[x]=1, son[x]=0;//!
for(int v=H[x]; v; v=nxt[v])
dep[v]=dep[x]+1, DFS1(v), sz[x]+=sz[v], sz[v]>mx&&(mx=sz[v],son[x]=v);
}
void DFS2(int x,int tp)
{
top[x]=tp, ref[dfn[x]=++Index]=x, vec[dep[x]].push_back(x);
if(son[x])
{
DFS2(son[x],tp);
for(int v=H[x]; v; v=nxt[v])
if(v!=son[x]) DFS2(v,v);
}
R[x]=Index;
}
void Solve()
{
int n=read(),m=read();
for(int i=1; i<=n; ++i) col[i]=read();
for(int i=2; i<=n; ++i) AE(fa[i]=read(),i);
dep[1]=1, DFS1(1), DFS2(1,1);
int mx=1;
for(int i=1; i<=n; ++i) mx=std::max(mx,dep[i]);
for(int i=1; i<=mx; ++i)
{
root[i]=root[i-1];
for(int j=0,l=vec[i].size(); j<l; ++j)
{
int x=vec[i][j],c=col[x];
if(!st[c].empty())
{
std::set<int>::iterator it=st[c].upper_bound(dfn[x]);
int nxt=it==st[c].end()?-1:ref[*it];
int pre=it==st[c].begin()?-1:ref[*(--it)];
int r1=LCA(pre,nxt),r2=LCA(pre,x),r3=LCA(x,nxt);
if(r1==r2 && r3!=-1) T.Modify(root[i],root[i],1,n,dfn[r3],-1);
else if(r1==r3 && r2!=-1) T.Modify(root[i],root[i],1,n,dfn[r2],-1);
}
T.Modify(root[i],root[i],1,n,dfn[x],1), st[c].insert(dfn[x]);
}
}
for(int i=1,ans=0; i<=m; ++i)
{
int x=read()^ans,k=read()^ans;
printf("%d\n",ans=T.Query(root[std::min(mx,dep[x]+k)],1,n,dfn[x],R[x]));
}
T.tot=0, Index=0, memset(H,0,n+1<<2);
for(int i=1; i<=n; ++i) std::set<int>().swap(st[i]);
for(int i=1; i<=mx; ++i) std::vector<int>().swap(vec[i]);
}
int main()
{
for(int T=read(); T--; Solve());
return 0;
}
BZOJ.4771.七彩树(可持久化线段树)的更多相关文章
- [BZOJ 4771]七彩树(可持久化线段树+树上差分)
[BZOJ 4771]七彩树(可持久化线段树+树上差分) 题面 给定一棵n个点的有根树,编号依次为1到n,其中1号点是根节点.每个节点都被染上了某一种颜色,其中第i个节点的颜色为c[i].如果c[i] ...
- 主席树||可持久化线段树+离散化 || 莫队+分块 ||BZOJ 3585: mex || Luogu P4137 Rmq Problem / mex
题面:Rmq Problem / mex 题解: 先离散化,然后插一堆空白,大体就是如果(对于以a.data<b.data排序后的A)A[i-1].data+1!=A[i].data,则插一个空 ...
- BZOJ 4771: 七彩树 可持久化线段树+树链的并
这个思路挺有意思的 ~ 利用树链的并来保证每个颜色只贡献一次,然后用可持久化线段树维护 code: #include <set> #include <cstdio> #incl ...
- BZOJ4771七彩树——可持久化线段树+set+树链的并+LCA
给定一棵n个点的有根树,编号依次为1到n,其中1号点是根节点.每个节点都被染上了某一种颜色,其中第i个节 点的颜色为c[i].如果c[i]=c[j],那么我们认为点i和点j拥有相同的颜色.定义dept ...
- BZOJ 3483 SGU505 Prefixes and suffixes(字典树+可持久化线段树)
[题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=3483 [题目大意] 给出一些串,同时给出m对前缀后缀,询问有多少串满足给出的前缀后缀模 ...
- bzoj 2653 二分答案+可持久化线段树
首先离散化,然后我们知道如果对于一个询问的区间[l1,r1],[l2,r2],我们二分到一个答案x,将[l1,r2]区间中的元素大于等于x的设为1,其余的设为-1,那么如果[l1,r1]的最大右区间和 ...
- BZOJ 3439 Kpm的MCpassword Trie树+可持久化线段树
题目大意:给定n个字符串,对于每一个字符串求以这个字符串为后缀的字符串中第k小的编号 首先将字符串反转 那么就变成了对于每一个字符串求以这个字符串为前缀的字符串中第k小的编号 然后考虑对字符串排序 那 ...
- 归并树 划分树 可持久化线段树(主席树) 入门题 hdu 2665
如果题目给出1e5的数据范围,,以前只会用n*log(n)的方法去想 今天学了一下两三种n*n*log(n)的数据结构 他们就是大名鼎鼎的 归并树 划分树 主席树,,,, 首先来说两个问题,,区间第k ...
- 主席树[可持久化线段树](hdu 2665 Kth number、SP 10628 Count on a tree、ZOJ 2112 Dynamic Rankings、codeforces 813E Army Creation、codeforces960F:Pathwalks )
在今天三黑(恶意评分刷上去的那种)两紫的智推中,突然出现了P3834 [模板]可持久化线段树 1(主席树)就突然有了不详的预感2333 果然...然后我gg了!被大佬虐了! hdu 2665 Kth ...
随机推荐
- bzoj 1951
这道题告诉了我们一个很重要的道理:看到题,先想明白再动手! 题意:求对999911659取模的值 首先,由于n的数据范围不是很大(至少不是很大),所以可以O()枚举所有约数分别求组合数 但是有个问题: ...
- idea首次创建新模块的详细操作
依赖网址:https://mvnrepository.com/artifact/javax.servlet/javax.servlet-api/3.1.0 https://mvnrepository. ...
- webpack学习笔记--配置devServer
devServer 1-6 使用DevServer 介绍过用来提高开发效率的 DevServer ,它提供了一些配置项可以改变 DevServer 的默认行为. 要配置 DevServer ,除了在配 ...
- golang 中操作nsq队列数据库
首先先在本地将服务跑起来,我用的是docker-compose ,一句话6666 先新建一个docker-compose.yml version: '2' services: nsqlookupd: ...
- MySQL主从备份配置实例
转载自:https://www.cnblogs.com/ahaii/p/6307648.html MySQL主从备份配置实例 场景: 1.主服务器192.168.0.225.从服务器192.168.0 ...
- 标准C语言实现基于TCP/IP协议的文件传输
TCP/IP编程实现远程文件传输在LUNIX中一般都采用套接字(socket)系统调用. 采用客户/服务器模式,其程序编写步骤如下: 1.Socket系统调用 为了进行网络I/O,服务器和客户机两 ...
- php把一些预定义的 HTML 实体转换为字符。
htmlspecialchars_decode() echo htmlspecialchars_decode($condition,ENT_QUOTES) ' 会被转成 单引号
- 一起学Hive——总结复制Hive表结构和数据的方法
在使用Hive的过程中,复制表结构和数据是很常用的操作,本文介绍两种复制表结构和数据的方法. 1.复制非分区表表结构和数据 Hive集群中原本有一张bigdata17_old表,通过下面的SQL语句可 ...
- 【Android】android:manageSpaceActivity让应用手动管理应用的数据目录
今天在Android遇到一个需求,不允许用户完全清除应用私有目录(/data/data/包名/),但是Android默认情况下用户通过在应用信息里面点击清除数据按钮把所有的应用私有目录下的的数据文件完 ...
- rxjs简单入门
rxjs全名Reactive Extensions for JavaScript,Javascript的响应式扩展, 响应式的思路是把随时间不断变化的数据.状态.事件等等转成可被观察的序列(Obser ...