题目大意:

给定一颗树,询问树中某个点x的子树中与其距离不超过d的所有点中本质不同的颜色数

强制在线

题解:

一下午终于把这道题叉掉了。

写了三个算法,前两个都是错的,后一个是%的网上大爷们的题解.

首先我们发现这道题有一个特点:没有修改操作 !!

这就使我们能够对颜色进行预处理。

所以我们可以考虑分别枚举每个颜色,对其去重后更新树上的信息。

所以我们可以考虑树链的并,我们可以对每种颜色都做一遍树链的并

容易发现复杂度仍然是\(O(nlogn)\)的

但是这样我们只求出来的每个节点子树中不同的颜色的个数

并没有满足对深度的限制

弱弱的我想到这里就继续不下去了,不知道下面改怎么写,YY了两个算法

第一个算法打着打着感觉不对,(Ctrl+A) + (Backspace)

第二个算法打出来了调样例,手模一下发现算法是错的.(Alt+F4)


去%了大爷们的题解:

我们把所有的点按照深度动态地进行树链的并.

这样,我们就发现我们实际上可以求出每一个深度到树根中不同颜色的种类

但是我们发现我们单单考虑了深度的一个边界还没有结束.

我们还需要限制深度另一个边界和在x子树中的限制

我们发现其实这两个限制等价于dfs序在x的子树dfs序范围之间.

所以。。。在深度上用线段树可持久化即可...

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cassert>
using namespace std;
typedef long long ll;
inline void read(int &x){
x=0;char ch;bool flag = false;
while(ch=getchar(),ch<'!');if(ch == '-') ch=getchar(),flag = true;
while(x=10*x+ch-'0',ch=getchar(),ch>'!');if(flag) x=-x;
}
const int maxn = 100010;
struct Edge{
int to,next;
}G[maxn<<2];
int head[maxn],cnt;
void add(int u,int v){
G[++cnt].to = v;
G[cnt].next = head[u];
head[u] = cnt;
}
int dfn[maxn],dfs_clock,son[maxn],siz[maxn];
int dep[maxn],top[maxn],fa[maxn],oud[maxn]; #define v G[i].to
void dfs(int u){
siz[u] = 1;
for(int i = head[u];i;i=G[i].next){
if(v == fa[u]) continue;
fa[v] = u;
dep[v] = dep[u] + 1;
dfs(v);
siz[u] += siz[v];
if(siz[son[u]] < siz[v]) son[u] = v;
}
}
void dfs(int u,int tp){
top[u] = tp;dfn[u] = ++dfs_clock;
if(son[u]) dfs(son[u],tp);
for(int i = head[u];i;i=G[i].next){
if(v == fa[u] || v == son[u]) continue;
dfs(v,v);
}
oud[u] = dfs_clock;
}
#undef v
inline int lca(int u,int v){
while(top[u] != top[v]){
if(dep[top[u]] < dep[top[v]]) swap(u,v);
u = fa[top[u]];
}return dep[u] < dep[v] ? u : v;
}
int col[maxn],n;
namespace Trp{
struct Node{
Node *ch[2];
int dfn,siz,fix,id;
void update(){
siz = ch[0]->siz + ch[1]->siz + 1;
}
}mem[maxn<<2],*it,*null,*root[maxn];
inline void init(){
it = mem;null = it++;
null->ch[0] = null->ch[1] = 0;null->id = -1;
null->dfn = null->siz = 0;
}
inline Node* newNode(int x,int i){
Node *p = it++;p->ch[0] = p->ch[1] = null;
p->dfn = x;p->fix = rand();
p->siz = 1;p->id = i;
return p;
}
void rotate(Node* &p,int k){
Node *y = p->ch[k^1];
p->ch[k^1] = y->ch[k];
y->ch[k] = p;
p->update();y->update();
p = y;
}
void insert(Node* &p,int x,int id){
if(p == null) p = newNode(x,id);
else{
insert(p->ch[p->dfn < x],x,id);
p->update();
if(p->ch[p->dfn<x]->fix < p->fix)
rotate(p,p->dfn > x);
}
}
inline int find(int k,Node *root){
Node *p = root;
if(k < 1 || k > p->siz) return -1;
while(p != null){
if(p->ch[0]->siz + 1 == k) return p->id;
if(p->ch[0]->siz + 1 > k) p = p->ch[0];
else k -= p->ch[0]->siz + 1,p = p->ch[1];
}assert(0);
}
inline int rank(int d,Node* root){
int ret = 1;Node *p = root;
while(p != null){
if(p->dfn < d) ret += p->ch[0]->siz + 1,p = p->ch[1];
else p = p->ch[0];
}return ret;
}
}
namespace seg{
struct Node{
Node* ch[2];
int val;
void update(){
val = ch[0]->val + ch[1]->val;
}
}mem[maxn*100],*it,*null,*root[maxn];
inline void init(){
it = mem;null = it++;
null->ch[0] = null->ch[1] = null;
null->val = 0;root[0] = null;
}
Node* insert(Node *rt,int l,int r,int pos,int w){
Node *p = it++;*p = *rt;
if(l == r){
p->val += w;
return p;
}
int mid = l+r >> 1;
if(pos <= mid) p->ch[0] = insert(p->ch[0],l,mid,pos,w);
else p->ch[1] = insert(p->ch[1],mid+1,r,pos,w);
p->update();return p;
}
int query(Node *p,int l,int r,int L,int R){
if(L <= l && r <= R) return p->val;
int mid = l+r >> 1;
if(R <= mid) return query(p->ch[0],l,mid,L,R);
if(L > mid) return query(p->ch[1],mid+1,r,L,R);
return query(p->ch[0],l,mid,L,R) + query(p->ch[1],mid+1,r,L,R);
}
}
int q[maxn],l,r,mx;
inline void bfs(){
l = 0;r = -1;q[++r] = 1;
while(l <= r){
int u = q[l++],x = Trp::rank(dfn[u],Trp::root[col[u]]),y,z;
mx = max(mx,dep[u]);
seg::root[dep[u]] = seg::insert(seg::root[dep[q[l-2]]],1,n,dfn[u],1);
Trp::insert(Trp::root[col[u]],dfn[u],u);
y = Trp::find(x-1,Trp::root[col[u]]);z = Trp::find(x+1,Trp::root[col[u]]);
if(y != -1 && z != -1){
int lc = lca(y,z);
seg::root[dep[u]] = seg::insert(seg::root[dep[u]],1,n,dfn[lc],1);
}
if(y != -1){
int lc = lca(y,u);
seg::root[dep[u]] = seg::insert(seg::root[dep[u]],1,n,dfn[lc],-1);
}
if(z != -1){
int lc = lca(z,u);
seg::root[dep[u]] = seg::insert(seg::root[dep[u]],1,n,dfn[lc],-1);
}
for(int i = head[u];i;i=G[i].next){
int v = G[i].to;
if(v == fa[u]) continue;
q[++r] = v;
}
}
}
inline void init(){
memset(head,0,sizeof head);cnt = 0;
memset(son,0,sizeof son);
memset(siz,0,sizeof siz);
dfs_clock = 0;mx = 0;
}
int main(){
int T;read(T);
srand(6613);
while(T--){
init();
seg::init();Trp::init();
int m;read(n);read(m);
for(int i=0;i<=n;++i){
Trp::root[i] = Trp::null;
seg::root[i] = seg::null;
}
for(int i=1;i<=n;++i) read(col[i]);
for(int i=2;i<=n;++i){
read(fa[i]);add(fa[i],i);
}dfs(1);dfs(1,1);
bfs();
int ans = 0;
int x,d;
while(m--){
read(x);read(d);
x ^= ans;d ^= ans;
int de = dep[x] + d;
if(de > mx) de = mx;
ans = seg::query(seg::root[de],1,n,dfn[x],oud[x]);
printf("%d\n",ans);
}
}
getchar();getchar();
return 0;
}

bzoj 4771: 七彩树 树链的并+可持久化线段树的更多相关文章

  1. BZOJ - 2588 Spoj 10628. Count on a tree (可持久化线段树+LCA/树链剖分)

    题目链接 第一种方法,dfs序上建可持久化线段树,然后询问的时候把两点之间的所有树链扒出来做差. #include<bits/stdc++.h> using namespace std; ...

  2. [BZOJ 3207] 花神的嘲讽计划Ⅰ【Hash + 可持久化线段树】

    题目链接:BZOJ - 3207 题目分析 先使用Hash,把每个长度为 k 的序列转为一个整数,然后题目就转化为了询问某个区间内有没有整数 x . 这一步可以使用可持久化线段树来做,虽然感觉可以有更 ...

  3. BZOJ.3218.a + b Problem(最小割ISAP 可持久化线段树优化建图)

    BZOJ UOJ 首先不考虑奇怪方格的限制,就是类似最大权闭合子图一样建图. 对于奇怪方格的影响,显然可以建一条边\((i\to x,p_i)\),然后由\(x\)向\(1\sim i-1\)中权值在 ...

  4. [BZOJ 4771]七彩树(可持久化线段树+树上差分)

    [BZOJ 4771]七彩树(可持久化线段树+树上差分) 题面 给定一棵n个点的有根树,编号依次为1到n,其中1号点是根节点.每个节点都被染上了某一种颜色,其中第i个节点的颜色为c[i].如果c[i] ...

  5. 计蒜客 38229.Distance on the tree-1.树链剖分(边权)+可持久化线段树(区间小于等于k的数的个数)+离散化+离线处理 or 2.树上第k大(主席树)+二分+离散化+在线查询 (The Preliminary Contest for ICPC China Nanchang National Invitational 南昌邀请赛网络赛)

    Distance on the tree DSM(Data Structure Master) once learned about tree when he was preparing for NO ...

  6. bzoj 2653 二分答案+可持久化线段树

    首先离散化,然后我们知道如果对于一个询问的区间[l1,r1],[l2,r2],我们二分到一个答案x,将[l1,r2]区间中的元素大于等于x的设为1,其余的设为-1,那么如果[l1,r1]的最大右区间和 ...

  7. Tsinsen A1505. 树(张闻涛) 倍增LCA,可持久化线段树,DFS序

    题目:http://www.tsinsen.com/A1505 A1505. 树(张闻涛) 时间限制:1.0s   内存限制:512.0MB    总提交次数:196   AC次数:65   平均分: ...

  8. [学习笔记] 可持久化线段树&主席树

    众所周知,线段树是一个非常好用也好写的数据结构, 因此,我们今天的前置技能:线段树. 然而,可持久化到底是什么东西? 别急,我们一步一步来... step 1 首先,一道简化的模型: 给定一个长度为\ ...

  9. [LOJ2310][APIO2017]斑斓之地——可持久化线段树

    题目链接: [APIO2017]斑斓之地 将不是河流的格子染成白色,是河流的格子染成黑色,那么连通块数就是白色格子数$-1*2$的联通白色格子数$-2*1$的联通白色格子数$+2*2$的联通白色格子数 ...

随机推荐

  1. Elasticsearch集群问题,导致主master节点发现不了node节点

    个人博客:https://blog.sharedata.info/ 最新需要配置es集群采用5个分片和1个副片,正好是11台机器,而只保留一份备份所以只需要5*2=10台机器方案:1.1台作为mast ...

  2. iPhone缓存网络数据

    本文转载至 http://blog.csdn.net/wwang196988/article/details/7542918   在iPhone应用程序中,我们经常要用去网络下载一些文件,比如xml, ...

  3. poj1845(二分快速求等比数列模M和)

    Sumdiv Time Limit: 1000MS   Memory Limit: 30000K Total Submissions: 17039   Accepted: 4280 Descripti ...

  4. 实用T-SQL代码

    1.根据出生日期计算当前已满周岁 DECLARE @birth datetime SET @birth='1990-01-01' ),) ),) 2.COUNT(expression) just re ...

  5. 7 Javascript:表单与验证-非空验证

    表单提交前要检查数据的合法性 在要对表单里的数据进行验证的时候,能够利用getElementById()来訪问网页上不论什么一个元素 每一个表单域都有一个form对象,可被传给不论什么验证表单数据的函 ...

  6. 安装了包,pycharm却提示找不到包

    这段时间,我爬虫爬到了一个论坛的数据,有个分析需要知道他的字符编码,因此使用到了 chardet,我在终端很顺利的安装了这个,但是在pycharm里使用的时候老是提示有错误,向下面这样: 其实这个是因 ...

  7. JPA 多表分页查询

    业务场景:大学生毕业后统计毕业去向.学生实体和毕业去向实体一对一关系. 实体: @Entity @Data @Table(name = "t_s_student") public ...

  8. 两个Java项目之间相互调用

    转自:http://dysfzhoulong.iteye.com/blog/1008747 一个项目A另一个项目B:(项目A和项目B都是Java写的项目) 在A项目中怎么调用B项目中的类和方法 有两种 ...

  9. 中国移动OnetNet云平台 使用WIFI模块ESP8266 TCP透传模式传输数据流步骤

    测试使用工具: WIFI模块型号:ESP8266 https://item.taobao.com/item.htm?spm=a1z10.1-c.w137712-175513579.2.btbD9X&a ...

  10. 小程序真机GET请求出现406错误

    问题:微信开发模拟器请求成功,获得数据,但是在真机上出现406请求错误,无法获得请求结果 原因:真机微信小程序的请求头与模拟器不同 怎么发现的:在请求头强制添加Accept即可解决 修复:在请求Hea ...