题目大意:

给定一颗树,询问树中某个点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. 使用Socket通信实现FTP客户端程序

    FTP 客户端如 FlashFXP,File Zilla 被广泛应用,原理上都是用底层的 Socket 来实现.FTP 客户端与服务器端进行数据交换必须建立两个套接字,一个作为命令通道,一个作为数据通 ...

  2. OpenCV玩耍(一)批量resize一个文件夹里的所有图像

    鉴于用caffe做实验的时候,里面牵扯到一个问题是必须将训练集和测试集都转成256*256的图像,而官网给出的代码又不会用,所以我用opencv转了.其实opencv只转一幅图会很简单,关键在于“批量 ...

  3. iOS基础动画的KeyPath取值

    一 .基础动画 1.基础动画的属性详解 注:Core Animation的动画执行过程都是在后台操作的,不会阻塞主线程. 属性 解读 Autoreverses 设定这个属性为 YES 时,在它到达目的 ...

  4. iOS启动页加载广告

    1.定义全局成员变量 @interface AppDelegate () @property (strong, nonatomic) UIImageView *adImageView; @proper ...

  5. 查看mysql支持的存储引擎

    查看mysql支持的存储引擎 show engines\G;

  6. [原创] hadoop学习笔记:wordcout程序实践

    看了官网上的示例:但是给的不是很清楚,这里依托官网给出的示例,加上自己的实践,解析worcount程序的操作 1.首先你的确定你的集群正确安装,并且启动你的集群,应为这个是hadoop2.6.0,所以 ...

  7. CustomizaitonSpec Clone_VM

    克隆虚拟机可以加上CustomizationSpec来自动配置好:IP地址.DNS.Domain等信息 1.可以利用PyVmimo中的vim模块在python中完全自定义CustomizationSp ...

  8. <HTTP协议详解>由浅入深看HTTP

    一. HTTP协议的应用简单概况 HTTP协议的主要特点可概括如下: 1.支持客户/服务器模式.2.简单快速:客户向服务器请求服务时,只需传送请求方法和路径.请求方法常用的有GET.HEAD.POST ...

  9. nginx location 语法

    location 语法location 有”定位”的意思, 根据Uri来进行不同的定位.在虚拟主机的配置中,是必不可少的,location可以把网站的不同部分,定位到不同的处理方式上.比如, 碰到.p ...

  10. java访问控制---java编程语言