首页 > bzoj 4771: 七彩树 树链的并+可持久化线段树

bzoj 4771: 七彩树 树链的并+可持久化线段树

题目大意:

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

强制在线

题解:

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

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

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

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

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

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

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

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

并没有满足对深度的限制

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

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

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


去%了大爷们的题解:

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

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

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

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

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

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

#include 
#include 
#include 
#include 
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->dfnfix < 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
",ans);}}getchar();getchar();return 0;
}

转载于:https://www.cnblogs.com/Skyminer/p/6556815.html

更多相关:

  •         Apache POI是一个开源的利用Java读写Excel,WORD等微软OLE2组件文档的项目。        我的需求是对Excel的数据进行导入或将数据以Excel的形式导出。先上简单的测试代码:package com.xing.studyTest.poi;import java.io.FileInputSt...

  • 要取得[a,b)的随机整数,使用(rand() % (b-a))+ a; 要取得[a,b]的随机整数,使用(rand() % (b-a+1))+ a; 要取得(a,b]的随机整数,使用(rand() % (b-a))+ a + 1; 通用公式:a + rand() % n;其中的a是起始值,n是整数的范围。 要取得a到b之间的...

  • 利用本征图像分解(Intrinsic Image Decomposition)算法,将图像分解为shading(illumination) image 和 reflectance(albedo) image,计算图像的reflectance image。 Reflectance Image 是指在变化的光照条件下能够维持不变的图像部分...

  • 题目:面试题39. 数组中出现次数超过一半的数字 数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字。 你可以假设数组是非空的,并且给定的数组总是存在多数元素。 示例 1: 输入: [1, 2, 3, 2, 2, 2, 5, 4, 2] 输出: 2 限制: 1 <= 数组长度 <= 50000 解题: cl...

  • 题目:二叉搜索树的后序遍历序列 输入一个整数数组,判断该数组是不是某二叉搜索树的后序遍历结果。如果是则返回 true,否则返回 false。假设输入的数组的任意两个数字都互不相同。 参考以下这颗二叉搜索树:      5     /    2   6   /  1   3示例 1: 输入: [1,6,3,2,5] 输出...

  • $dp$。 这道题最关键的是这句话: 跳出思维局限大胆设状态,设$f_{x, i, j}$表示从$x$到根要经过$i$条公路,$j$条铁路的代价,那么对于一个叶子结点,有$f_{x, i, j} = c_x * (a_x + i) * (b_x + j)$,对于内部结点,有转移:   $f_{x, i, j} = min(f_{lso...

  • 合作者:201631062327,201631062128码云地址:https://gitee.com/LIUJIA6/WordCount3 一:项目说明 本次项目是在上次作业WorldCount的基础上,利用结对编程的思想,完成对WorldCount项目的功能扩展 -s 递归处理目录下符合条件的文件。(实现)-a 返回更复杂的数据(...

  • Description 魔咒串由许多魔咒字符组成,魔咒字符可以用数字表示。例如可以将魔咒字符 1、2 拼凑起来形成一个魔咒串 [1,2]。 一个魔咒串 S 的非空字串被称为魔咒串 S 的生成魔咒。 例如 S=[1,2,1] 时,它的生成魔咒有 [1]、[2]、[1,2]、[2,1]、[1,2,1] 五种。S=[1,1,1] 时,它的生...

  •   【题目链接】 http://acm.hdu.edu.cn/showproblem.php?pid=5972   【题目大意】   给出一个字符串,找出其中所有的符合特定模式的子串位置,符合特定模式是指,该子串的长度为n,并且第i个字符需要在给定的字符集合Si中    【题解】   利用ShiftAnd匹配算法。   bt[i]表示...

  • 首先我们可以发现如果错过了一个加油站,而继续往前走的时候没有油了,可以再假装之前经过加油站的时候加过油 于是我们维护一个大根堆,表示错过的加油站是哪些,每当没有油的时候从堆顶取出最大值加上去即可   1 /**************************************************************...

  • #include #include #include #include #include #include #include

  • 题目:表示数值的字符串 请实现一个函数用来判断字符串是否表示数值(包括整数和小数)。例如,字符串"+100"、"5e2"、"-123"、"3.1416"、"0123"及"-1E-16"都表示数值,但"12e"、"1a3.14"、"1.2.3"、"+-5"及"12e+5.4"都不是。 解题: 数值错误的形式有多种多样,但是正确的...

  • 加法伺候  //超过20位数值相加---------------------------------------- function bigNumAdd(a, b) {if (!(typeof a === "string" && typeof b === "string")) return console.log("传入参数必...

  • 业务场景: 从中文字句中匹配出指定的中文子字符串 .这样的情况我在工作中遇到非常多, 特梳理总结如下. 难点: 处理GBK和utf8之类的字符编码, 同时正则匹配Pattern中包含汉字,要汉字正常发挥作用,必须非常谨慎.推荐最好统一为utf8编码,如果不是这种最优情况,也有酌情处理. 往往一个具有普适性的正则表达式会简化程...

  • 简单record 一下 #include // 'struct sockaddr_in' #include #include // 'struct ifreq' and 'struct if_nameindex' #include #inc...