BZOJ 4771 七彩树(可持久化线段树合并)
题意
https://www.lydsy.com/JudgeOnline/problem.php?id=4771
思路
和 HDU 3333 其实有点像,不过是把序列的问题放在了树上,多维护一个深度即可。每个点用一个线段树维护子树内每个深度有多少种颜色(同样只保留每个颜色最浅位置),用线段树合并进行合并,由于要保留之前的颜色,所以合并应该可持久化。
为了将相同的颜色去除,再开一个线段树维护每个颜色目前的深度,若合并时出现重复情况,把深的颜色删去(也在维护深度的线段树中删去),代码比较难调。
代码
#include<bits/stdc++.h>
#define FOR(i,x,y) for(int i=(x),i##END=(y);i<=i##END;++i)
#define DOR(i,x,y) for(int i=(x),i##END=(y);i>=i##END;--i)
typedef long long LL;
using namespace std;
const int N=1e5+5;
const int NN1=N*180;
const int NN2=N*25;
template<const int maxn,const int maxm>struct Linked_list
{
int head[maxn],to[maxm],nxt[maxm],tot;
Linked_list(){clear();}
void clear(){memset(head,-1,sizeof(head));tot=0;}
void add(int u,int v){to[++tot]=v,nxt[tot]=head[u],head[u]=tot;}
#define EOR(i,G,u) for(int i=G.head[u];~i;i=G.nxt[i])
};
Linked_list<N,N>G;
int dep[N],col[N],n,m;
struct SegmentTree1
{
int sum[NN1],lson[NN1],rson[NN1];
int rt[N],tot;
int &operator [](const int &x){return rt[x];}
void build()
{
memset(rt,0,sizeof(rt));
sum[tot=0]=lson[0]=rson[0]=0;
}
void Create(int &k)
{
sum[++tot]=sum[k],lson[tot]=lson[k],rson[tot]=rson[k],k=tot;
}
void update(int &k,int x,int val,int l,int r)
{
Create(k);
sum[k]+=val;
if(l==r)return;
int mid=(l+r)>>1;
if(x<=mid)update(lson[k],x,val,l,mid);
else update(rson[k],x,val,mid+1,r);
}
int query(int k,int L,int R,int l,int r)
{
if(L<=l&&r<=R)return sum[k];
int mid=(l+r)>>1;
if(R<=mid)return query(lson[k],L,R,l,mid);
else if(L>mid)return query(rson[k],L,R,mid+1,r);
else return query(lson[k],L,R,l,mid)+query(rson[k],L,R,mid+1,r);
}
void merge(int &x,int y,int l,int r)
{
if(!x||!y){x=(x|y);return;}
Create(x);
if(l==r){sum[x]+=sum[y];return;}
int mid=(l+r)>>1;
merge(lson[x],lson[y],l,mid);
merge(rson[x],rson[y],mid+1,r);
sum[x]=sum[lson[x]]+sum[rson[x]];
}
}ST1;
//ST1[i] 以i为根的子树,每个深度有多少个节点(不同色)
struct SegmentTree2
{
int lson[NN2],rson[NN2];
int Mi[NN2],rt[N],tot;
int &operator [](const int &x){return rt[x];}
void build()
{
memset(rt,0,sizeof(rt));
Mi[tot=0]=1e9;
lson[0]=rson[0]=0;
}
void create(int &k)
{
if(!k)k=++tot,Mi[k]=1e9,lson[k]=rson[k]=0;
}
void update(int &k,int x,int val,int l,int r)
{
create(k);
if(l==r){Mi[k]=min(Mi[k],val);return;}
int mid=(l+r)>>1;
if(x<=mid)update(lson[k],x,val,l,mid);
else update(rson[k],x,val,mid+1,r);
}
int query(int k,int x,int l,int r)
{
if(l==r)return Mi[k];
int mid=(l+r)>>1;
if(x<=mid)return query(lson[k],x,l,mid);
else return query(rson[k],x,mid+1,r);
}
void merge(int &x,int y,int &id,int l,int r)
{
if(!x||!y){x=(x|y);return;}
if(l==r)
{
ST1.update(id,max(Mi[x],Mi[y]),-1,1,n);
Mi[x]=min(Mi[x],Mi[y]);
return;
}
int mid=(l+r)>>1;
merge(lson[x],lson[y],id,l,mid);
merge(rson[x],rson[y],id,mid+1,r);
}
}ST2;
//ST2[i] 以i为根的子树,每种颜色出现的最浅深度
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
G.clear();
scanf("%d%d",&n,&m);
FOR(i,1,n)scanf("%d",&col[i]);
dep[1]=1;
FOR(v,2,n)
{
int u;
scanf("%d",&u);
G.add(u,v);
dep[v]=dep[u]+1;
}
ST1.build(),ST2.build();
DOR(u,n,1)
{
ST1.update(ST1[u],dep[u],1,1,n);
ST2.update(ST2[u],col[u],dep[u],1,n);
EOR(i,G,u)
{
int v=G.to[i];
ST1.merge(ST1[u],ST1[v],1,n);
ST2.merge(ST2[u],ST2[v],ST1[u],1,n);
}
}
int x,d,lst=0;
while(m--)
{
scanf("%d%d",&x,&d);
x^=lst,d^=lst;
printf("%d\n",lst=ST1.query(ST1[x],dep[x],min(n,dep[x]+d),1,n));
}
}
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.七彩树(可持久化线段树)
BZOJ 考虑没有深度限制,对整棵子树询问怎么做. 对于同种颜色中DFS序相邻的两个点\(u,v\),在\(dfn[u],dfn[v]\)处分别\(+1\),\(dfn[LCA(u,v)]\)处\(- ...
- 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 ...
随机推荐
- skynet对Windows环境支持的版本:Windows版skynet
https://github.com/sanikoyes/skynet.git Skynet Skynet is a lightweight online game framework, and it ...
- OBO文件格式1.2
该文件每一行都是一个键值对,基本格式为: 键: 值!注释 总体结构: 文件头 !包含若干行总体说明 词条1 ![词条类型]占第一行,后跟若干行说明 词条2 ! ...
- 1 virtual
1 differents: 'virtual' just in C# In Java It does't have the keyword 2 Usages in C# used in base cl ...
- 文本tfidf
文本分类tf:词的频率 idf:逆文档频率 代码实例: # tf idf from sklearn.feature_extraction.text import TfidfVectorizer imp ...
- linux 文件压缩与解压缩
- 记账本微信小程序开发三
一.制作登陆界面: 更改全局配置,改颜色,名称: 界面 格式 登录界面 二.页面的跳转 按钮的设置 注册事件 结果
- 一个讲课截屏 清明DAY2
灰常混乱 放弃吧........ 不断做平方差公式 到i时,前面已经求出之前数字的逆元了 r是一个比i小的数 第四行×i,r 的逆元 BSGS 暴力枚举枚举到Φ(m)个
- 怎样从外网访问内网Oracle数据库?
本地安装了一个Oracle数据库,只能在局域网内访问到,怎样从外网也能访问到本地的Oracle数据库呢?本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装并启动Oracle数据库 默认安装的Or ...
- c#测试执行时间的方法
获取当前实例测量出来的总的运行时间 Stopwatch sp = new Stopwatch(); sp.Start(); //要测试的代码块 sp.Stop(); Console.WriteLine ...
- 【视频】使用fiddler开发工具进行新架构页面本地调试
[视频]使用fiddler开发工具进行新架构页面本地调试,视频没录制好,有些部分比较模糊...