把LCA深度转化的那一步还是挺妙的。之后就是差分加大力数据结构了。

Description

给出一个n个节点的有根树(编号为0到n-1,根节点为0)。一个点的深度定义为这个节点到根的距离+1。
设dep[i]表示点i的深度,LCA(i,j)表示i与j的最近公共祖先。
有q次询问,每次询问给出l r z,求sigma_{l<=i<=r}dep[LCA(i,z)]。
(即,求在[l,r]区间内的每个节点i与z的最近公共祖先的深度之和)

Input

第一行2个整数n q。
接下来n-1行,分别表示点1到点n-1的父节点编号。
接下来q行,每行3个整数l r z。

Output

输出q行,每行表示一个询问的答案。每个答案对201314取模输出

Sample Input

5 2
0
0
1
1
1 4 3
1 4 2

Sample Output

8
5

HINT

共5组数据,n与q的规模分别为10000,20000,30000,40000,50000。


题目分析

我的做法&图片分析

由于树的标号是随便标的,所以这里的$[l,r]$区间操作在树上并没有什么大的特殊意义。

注意到如果$z$是给定的话,那么由于答案可减,我们可以对于序列来分块。

当然分块只是一种想法,再来挖掘一下$z$给定情况的性质。

这里求4和7的LCA。自然,LCA就是两点到根节点的第一个公共节点。不过这幅图可能还没看出什么。

这幅图里7号节点是z,4,6,8节点是与z节点查询的节点。我们把与z节点查询的节点都沿路径向根方向+1。

这样只需要查询z节点到根节点的路径权值和就能算出所有LCA的深度之和了。

注意到这样处理之后,预处理的信息对于任意的z都适用了。

至于题目要求的“根节点深度为1”,正好可以让我们把边权化为点权,做起来也更加方便。

更理论化的题解

在黄学长博客上看到一篇更加严谨的题解:

显然,暴力求解的复杂度是无法承受的。
考虑这样的一种暴力,我们把 z 到根上的点全部打标记,对于 l 到 r 之间的点,向上搜索到第一个有标记的点求出它的深度统计答案。观察到,深度其实就是上面有几个已标记了的点(包括自身)。所以,我们不妨把 z 到根的路径上的点全部 +1,对于 l 到 r 之间的点询问他们到根路径上的点权和。仔细观察上面的暴力不难发现,实际上这个操作具有叠加性,且可逆。也就是说我们可以对于 l 到 r 之间的点 i,将 i 到根的路径上的点全部 +1, 转而询问 z 到根的路径上的点(包括自身)的权值和就是这个询问的答案。把询问差分下,也就是用 [1, r] − [1, l − 1] 来计算答案,那么现在我们就有一个明显的解法。从 0 到 n − 1 依次插入点 i,即将 i 到根的路径上的点全部+1。离线询问答案即可。我们现在需要一个数据结构来维护路径加和路径求和,显然树链剖分或LCT 均可以完成这个任务。树链剖分的复杂度为 O((n + q)· log n · log n),LCT的复杂度为 O((n + q)· log n),均可以完成任务。至此,题目已经被我们完美解决。

(大力数据结构~)

 #include<bits/stdc++.h>
const int MO = ;
const int maxn = ;
const int maxm = ; struct node
{
int fa,top,son,tot;
}a[maxn];
struct QRs
{
int x,id,opt;
QRs(int a=, int b=, int c=):x(a),id(b),opt(c) {}
bool operator < (QRs a) const
{
return x < a.x;
}
}q[maxn<<];
int chain[maxn],chTot;
int f[maxn<<],add[maxn<<];
int edges[maxm],nxt[maxm],head[maxn],edgeTot;
int ansAdd[maxn],ansDel[maxn],qr[maxn];
int n,m,tot; int read()
{
char ch = getchar();
int num = ;
bool fl = ;
for (; !isdigit(ch); ch = getchar())
if (ch=='-') fl = ;
for (; isdigit(ch); ch = getchar())
num = (num<<)+(num<<)+ch-;
if (fl) num = -num;
return num;
}
void addedge(int u, int v)
{
edges[++edgeTot] = v, nxt[edgeTot] = head[u], head[u] = edgeTot;
}
void dfs1(int x, int fa)
{
a[x].fa = fa, a[x].son = -, a[x].tot = ;
for (int i=head[x]; i!=-; i=nxt[i])
{
int v = edges[i];
dfs1(v, x), a[x].tot += a[v].tot;
if (a[x].son==-||a[a[x].son].tot < a[v].tot)
a[x].son = v;
}
}
void dfs2(int x, int top)
{
chain[x] = ++chTot, a[x].top = top;
if (a[x].son==-) return;
dfs2(a[x].son, top);
for (int i=head[x]; i!=-; i=nxt[i])
if (edges[i]!=a[x].son)
dfs2(edges[i], edges[i]);
}
void pushup(int x)
{
f[x] = (f[x<<]+f[x<<|])%MO;
}
void pushdown(int x, int l, int r)
{
if (add[x]){
add[x<<] += add[x], add[x<<|] += add[x];
f[x<<] += l*add[x], f[x<<|] += r*add[x];
f[x<<] %= MO, f[x<<|] %= MO;
add[x] = ;
}
}
void update(int rt, int L, int R, int l, int r)
{
if (L <= l&&r <= R){
add[rt]++, f[rt] = (f[rt]+r-l+)%MO;
return;
}
int mid = (l+r)>>;
pushdown(rt, mid-l+, r-mid);
if (L <= mid) update(rt<<, L, R, l, mid);
if (R > mid) update(rt<<|, L, R, mid+, r);
pushup(rt);
}
void updateChain(int x, int y)
{
while (a[x].top!=a[y].top)
{
update(, chain[a[x].top], chain[x], , n);
x = a[a[x].top].fa;
}
update(, chain[y], chain[x], , n);
}
int query(int rt, int L, int R, int l, int r)
{
if (L <= l&&r <= R) return f[rt];
int mid = (l+r)>>, ret = ;
pushdown(rt, mid-l+, r-mid);
if (L <= mid) ret += query(rt<<, L, R, l, mid);
if (R > mid) ret += query(rt<<|, L, R, mid+, r);
return ret%MO;
}
int queryChain(int x, int y)
{
int ret = ;
while (a[x].top!=a[y].top)
{
ret += query(, chain[a[x].top], chain[x], , n);
x = a[a[x].top].fa;
}
ret += query(, chain[y], chain[x], , n);
return ret%MO;
}
int main()
{
memset(head, -, sizeof head);
n = read(), m = read();
for (int i=; i<n; i++) addedge(read(), i);
for (int i=; i<=m; i++)
{
q[++tot] = QRs(read()-, i, ), q[++tot] = QRs(read(), i, );
qr[i] = read();
}
std::sort(q+, q+tot+);
dfs1(, -);
dfs2(, );
int now = -;
for (int i=; i<=tot; i++)
{
while (now < q[i].x)
updateChain(++now, );
int id = q[i].id;
if (q[i].opt)
ansAdd[id] = queryChain(qr[id], );
else ansDel[id] = queryChain(qr[id], );
}
for (int i=; i<=m; i++)
printf("%d\n",(ansAdd[i]-ansDel[i]+MO)%MO);
return ;
}

END

【树链剖分 差分】bzoj3626: [LNOI2014]LCA的更多相关文章

  1. 树链剖分与倍增求LCA

    树链剖分与倍增求\(LCA\) 首先我要吐槽机房的辣基供电情况,我之前写了一上午,马上就要完成的时候突然停电,然后\(GG\)成了送链剖分 其次,我没歧视\(tarjan LCA\) 1.倍增求\(L ...

  2. BZOJ 3626 LCA(离线+树链剖分+差分)

    显然,暴力求解的复杂度是无法承受的. 考虑这样的一种暴力,我们把 z 到根上的点全部打标记,对于 l 到 r 之间的点,向上搜索到第一个有标记的点求出它的深度统计答案.观察到,深度其实就是上面有几个已 ...

  3. HDU 5452——Minimum Cut——————【树链剖分+差分前缀和】ACdream 1429——Diversion——————【树链剖分】

    Minimum Cut Time Limit: 3000/2000 MS (Java/Others)    Memory Limit: 65535/102400 K (Java/Others)Tota ...

  4. 洛谷 P3258 [JLOI2014]松鼠的新家 树链剖分+差分前缀和优化

    目录 题面 题目链接 题目描述 输入输出格式 输入格式 输出格式 输入输出样例 输入样例: 输出样例: 说明 说明 思路 AC代码 优化 优化后AC代码 总结 题面 题目链接 P3258 [JLOI2 ...

  5. 【线段树 树链剖分 差分 经典技巧】loj#3046. 「ZJOI2019」语言【未完】

    还是来致敬一下那过往吧 题目分析 先丢代码 #include<bits/stdc++.h> ; ; ; struct node { int top,son,fa,tot; }a[maxn] ...

  6. 树链剖分(附带LCA和换根)——基于dfs序的树上优化

    .... 有点懒: 需要先理解几个概念: 1. LCA 2. 线段树(熟练,要不代码能调一天) 3. 图论的基本知识(dfs序的性质) 这大概就好了: 定义: 1.重儿子:一个点所连点树size最大的 ...

  7. [BZOJ3626] [LNOI2014]LCA(树链剖分)

    [BZOJ3626] [LNOI2014]LCA(树链剖分) 题面 给出一棵N个点的树,要求支持Q次询问,每次询问一个点z与编号为区间[l,r]内的点分别求最近公共祖先得到的最近公共祖先深度和.N, ...

  8. 【树链剖分】【线段树】bzoj3626 [LNOI2014]LCA

    引用题解: http://blog.csdn.net/popoqqq/article/details/38823457 题目大意: 给出一个n个节点的有根树(编号为0到n-1,根节点为0).一个点的深 ...

  9. 【BZOJ3626】LCA(树上差分,树链剖分)

    题意:给出一个n个节点的有根树(编号为0到n-1,根节点为0).一个点的深度定义为这个节点到根的距离+1.设dep[i]表示点i的深度,LCA(i,j)表示i与j的最近公共祖先.有q次询问,每次询问给 ...

随机推荐

  1. cell内存优化

    UITableView的常用属性: 分割线颜色设置: 1> 设置separatorStyle: 分割线的颜色 方法:tableView.separatorStyle = UITableViewC ...

  2. PostgreSQL - N''和::bpchar

    N''的效果和::bpchar效果类似,都表示定长字符串.比如下边的sql: select n'233' as num; select '233'::bpchar as num; select '23 ...

  3. PostgreSQL-5-条件过滤

    基本语法 SELECT column1, column2, columnN FROM table_name WHERE [search_condition] 操作符 =等于:<>不等于:! ...

  4. iOS开发:创建推送开发证书和生产证书,以及往极光推送官网上传证书的步骤方法

    在极光官网上面上传应用的极光推送证书的实质其实就是上传导出的p12文件,在极光推送应用管理里面,需要上传两个p12文件,一个是生产证书,一个是开发证书 ,缺一不可,具体如下所示: 在开发者账号里面创建 ...

  5. Jasper_crosstab_Parameter_Crosstab Header

    corsstab: Q : how to show filed value at crosstab Header Part? A : via pass parameter in crosstab. i ...

  6. Azkaban是什么?(一)

    不多说,直接上干货! http://www.cnblogs.com/zlslch/category/938837.html Azkaban是什么?  Azkaban是一套简单的任务调度服务,整体包括三 ...

  7. JavaMailSender怎么发送163和qq邮件

    https://blog.csdn.net/Tracycater/article/details/73441010 引入Maven依赖包 <dependency> <groupId& ...

  8. Nginx 开启目录浏览功能配置

    在server节点下添加 server { listen ; server_name default; #index index.php; # 目录浏览功能 autoindex on; # 显示文件大 ...

  9. Spring相关BUG

    今天从云开发平台上生成的代码报Spring相关的错误. 我找到第一处错误,整理如下: org.springframework.beans.factory.BeanCreationException: ...

  10. git命令收集

    $ git clone ... $ git status 查看状态 $ git commit -am "XXX" 提交信息 $ git commit -am "XXXX& ...