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 ...
随机推荐
- Hive 数仓中常见的日期转换操作
(1)Hive 数仓中一些常用的dt与日期的转换操作 下面总结了自己工作中经常用到的一些日期转换,这类日期转换经常用于报表的时间粒度和统计周期的控制中 日期变换: (1)dt转日期 to_date(f ...
- AtCoder Beginner Contest 043 D - アンバランス / Unbalanced
题目链接:http://abc043.contest.atcoder.jp/tasks/arc059_b Time limit : 2sec / Memory limit : 256MB Score ...
- JustOj 2042: Dada的游戏
题目描述 Dada无聊时,喜欢做一个游戏,将很多钱分成若干堆排成一列,每堆钱数不固定,谁能找出每堆钱数严格递增的最长区间,谁就是人生赢家了.Dada可能脑子里的水还没干,她找不出来,你来帮她找找吧. ...
- Linux系统管理和维护常用命令
Linux系统管理和维护常用命令 ls 命令 功能说明 ls 命令显示指定工作目录下的内容,列出工作目录所包含的文件及子目录. 语法结构: ls [选项] [路径或文件] ls 选项及说明 -a 显示 ...
- 给web项目整合富文本编辑器
给jsp页面整合富文本编辑器下载——删除多余的组件——加入到项目中——参照案例来完成整合步骤:1. 解压zip文件,将所有文件复制到Tomcat的webapps/kindeditor目录下. 2. 将 ...
- A-作业01
#1 简单作业 1. 系统的日志文件/var/log/secure /var/log/messages /var/log/cron会自动的进行轮询,系统是通过什么实现的? 2. 写出下面特殊符号在定时 ...
- Vue小案例 之 商品管理------删除商品与提示
实现删除商品功能 根据索引来进行删除商品: 实现删除商品的HTML: <!--显示表格--> <div class="table-warp"> <di ...
- P2709 小B的询问(莫队)
P2709 小B的询问 莫队模板 资磁离线询问 维护两个跳来跳去的指针 先分块,蓝后询问按块排序. 蓝后每次指针左右横跳更新答案 #include<iostream> #include&l ...
- 【题解】Luogu P2073 送花
原题传送门 这题需要用到Splay 我们用一棵splay维护金钱 考虑c<=1000000 我们珂以把每种价格现在对应的美丽值存在一个a数组中 这样讲有珂能不太清楚qaq,还是对着操作一个一个讲 ...
- 公网FTP(filezilla)改端口
背景:我们如果不修改ftp服务器的端口,很容易被别人测试和攻击. 配置要点:服务端端口设置.主被动设置.服务端和客户端防火墙设置 ftp服务器:filezilla ftp server 1. 监听端 ...