题目大意:

给定一颗树,询问树中某个点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. Visual Studion 2013 HTML 如何打开设计图

    Visual Studion 2013 HTML 没有设计视图? 在解决方案中对要打开的HTML文件 右键-->打开方式-->HTML(Web窗体)编辑器 原地址>>:http ...

  2. hdu3293(pell方程+快速幂)

    裸的pell方程. 然后加个快速幂. No more tricks, Mr Nanguo Time Limit: 3000/1000 MS (Java/Others)    Memory Limit: ...

  3. android菜鸟学习笔记21----ContentProvider(一)ContentProvider的简单使用

    ContentProvider是Android四大组件之一,它用来封装数据,并通过ContentResolver接口将数据提供给其他应用.只有当需要在多个应用之间共享数据时才会用到ContentPro ...

  4. 九度OJ 1200:最大的两个数 (最值)

    时间限制:1 秒 内存限制:32 兆 特殊判题:否 提交:2904 解决:761 题目描述: 输入一个四行五列的矩阵,找出每列最大的两个数. 输入: 输入第一行包括一个整数n(1<=n<= ...

  5. recognition rate generalization识别率 泛化

    http://www1.inf.tu-dresden.de/~ds24/lehre/ml_ws_2013/ml_11_hinge.pdf Two extremes: • Big

  6. spring data jpa 利用@Query进行查询

    参照https://blog.csdn.net/yingxiake/article/details/51016234#reply https://blog.csdn.net/choushi300/ar ...

  7. Oracle视图传递参数

    在Oracle里,视图不像存储过程和函数一样,可以定义输入参数,但我们可以变个方式,使用程序包来实现. oracle package: oracle package是oracle包,是一组相关过程.函 ...

  8. 深入理解ByteBuffer(转)

    转:http://blog.csdn.net/workformywork/article/details/26699345?utm_source=tuicool&utm_medium=refe ...

  9. Nvidia NVENC 硬编码预研总结

    本篇博客记录NVENC硬编码的预研过程 github:  https://github.com/MarkRepo/NvencEncoder 步骤如下: (1)环境搭建 (2)demo编译,测试,ARG ...

  10. 读:Instance-aware Image and Sentence Matching with Selective Multimodal LSTM

    摘要:有效图像和句子匹配取决于如何很好地度量其全局视觉 - 语义相似度.基于观察到这样的全局相似性是由图像(对象)和句子(词)的成对实例之间的多个局部相似性的复合聚集,我们提出了一个实例感知图像和句子 ...