BZOJ 3626 [LNOI2014]LCA:树剖 + 差分 + 离线【将深度转化成点权之和】
题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=3626
题意:
给出一个n个节点的有根树(编号为0到n-1,根节点为0,n <= 50000)。
一个点的深度定义为这个节点到根的距离+1。
设dep[i]表示点i的深度,LCA(i,j)表示i与j的最近公共祖先。
有q次询问,每次询问给出l,r,z,求∑ dep[LCA(i,z)] (l<=i<=r)。
(即,求在[l,r]区间内的每个节点i与z的最近公共祖先的深度之和)
题解:
假设有一棵所有点都为0的树。
如果将x到root路径上的点都+1,则dep[LCA(x,y)] = y到root路径上的点权之和,且这个操作具有叠加性。(树剖)
所以对于询问query(l to r) = query(r) - query(l-1)。(差分)
显然,只需要求出在询问中有的l和r的query。
所以依次枚举节点i = 0 to n-1,将i到root的路径+1,如果i是某一些询问的l或r,则记录相应的query(z)。(离线)
总复杂度O((n+q)*logn*logn)
AC Code:
#include <iostream>
#include <stdio.h>
#include <string.h>
#include <vector>
#define MAX_N 200005
#define MAX_M 50005
#define MOD 201314 using namespace std; struct Query
{
int ver;
int id;
int dr;
Query(int _ver,int _id,int _dr)
{
ver=_ver;
id=_id;
dr=_dr;
}
Query(){};
}; int n,m;
int tot=;
int cnt=;
int l[MAX_M];
int r[MAX_M];
int z[MAX_M];
int dat[MAX_N];
int lazy[MAX_N];
int lson[MAX_N];
int rson[MAX_N];
int par[MAX_N];
int dep[MAX_N];
int siz[MAX_N];
int tp[MAX_N];
int son[MAX_N];
int dfsx[MAX_N];
int ans[MAX_M][];
vector<int> edge[MAX_N];
vector<Query> q[MAX_M]; inline int mod(int x)
{
return (x%MOD+MOD)%MOD;
} int build(int l,int r)
{
int rt=++tot;
dat[rt]=lazy[rt]=;
lson[rt]=rson[rt]=;
if(l<r)
{
int mid=(l+r)>>;
lson[rt]=build(l,mid);
rson[rt]=build(mid+,r);
}
return rt;
} void push_down(int k,int len)
{
if(lazy[k])
{
if(lson[k])
{
dat[lson[k]]=mod(dat[lson[k]]+lazy[k]*(len-(len>>)));
lazy[lson[k]]=mod(lazy[lson[k]]+lazy[k]);
}
if(rson[k])
{
dat[rson[k]]=mod(dat[rson[k]]+lazy[k]*(len>>));
lazy[rson[k]]=mod(lazy[rson[k]]+lazy[k]);
}
lazy[k]=;
}
} void push_up(int k)
{
dat[k]=;
if(lson[k]) dat[k]=mod(dat[k]+dat[lson[k]]);
if(rson[k]) dat[k]=mod(dat[k]+dat[rson[k]]);
} void update(int a,int b,int k,int l,int r,int x)
{
if(a<=l && r<=b)
{
dat[k]=mod(dat[k]+(r-l+)*x);
lazy[k]=mod(lazy[k]+x);
return;
}
if(r<a || b<l) return;
push_down(k,r-l+);
int mid=(l+r)>>;
update(a,b,lson[k],l,mid,x);
update(a,b,rson[k],mid+,r,x);
push_up(k);
} int query(int a,int b,int k,int l,int r)
{
if(a<=l && r<=b) return dat[k];
if(r<a || b<l) return ;
push_down(k,r-l+);
int mid=(l+r)>>;
int v1=query(a,b,lson[k],l,mid);
int v2=query(a,b,rson[k],mid+,r);
return mod(v1+v2);
} void dfs1(int now,int d)
{
dep[now]=d;
siz[now]=;
for(int i=;i<edge[now].size();i++)
{
int temp=edge[now][i];
if(temp!=par[now])
{
dfs1(temp,d+);
siz[now]+=siz[temp];
}
}
} void dfs2(int now,int anc)
{
tp[now]=anc;
son[now]=-;
dfsx[now]=++cnt;
for(int i=;i<edge[now].size();i++)
{
int temp=edge[now][i];
if((son[now]==- || siz[temp]>siz[son[now]]) && temp!=par[now])
{
son[now]=temp;
}
}
if(son[now]!=-) dfs2(son[now],anc);
for(int i=;i<edge[now].size();i++)
{
int temp=edge[now][i];
if(temp!=par[now] && temp!=son[now]) dfs2(temp,temp);
}
} void update_chain(int a,int x)
{
while(tp[a]!=)
{
update(dfsx[tp[a]],dfsx[a],,,n,x);
a=par[tp[a]];
}
update(,dfsx[a],,,n,x);
} int query_chain(int a)
{
int sum=;
while(tp[a]!=)
{
sum=mod(sum+query(dfsx[tp[a]],dfsx[a],,,n));
a=par[tp[a]];
}
sum=mod(sum+query(,dfsx[a],,,n));
return sum;
} void read()
{
scanf("%d%d",&n,&m);
for(int i=;i<n;i++)
{
scanf("%d",&par[i]);
edge[i].push_back(par[i]);
edge[par[i]].push_back(i);
}
} void solve()
{
build(,n);
dfs1(,);
dfs2(,);
for(int i=;i<m;i++)
{
scanf("%d%d%d",&l[i],&r[i],&z[i]);
if(l[i]>) q[l[i]-].push_back(Query(z[i],i,));
q[r[i]].push_back(Query(z[i],i,));
}
memset(ans,,sizeof(ans));
for(int i=;i<n;i++)
{
update_chain(i,);
for(int j=;j<q[i].size();j++)
{
Query temp=q[i][j];
ans[temp.id][temp.dr]=query_chain(temp.ver);
}
}
} void print()
{
for(int i=;i<m;i++)
{
printf("%d\n",mod(ans[i][]-ans[i][]));
}
} int main()
{
read();
solve();
print();
}
BZOJ 3626 [LNOI2014]LCA:树剖 + 差分 + 离线【将深度转化成点权之和】的更多相关文章
- BZOJ 3626: [LNOI2014]LCA(树剖+差分+线段树)
传送门 解题思路 比较有意思的一道题.首先要把求\(\sum\limits_{i=l}^r dep[lca(i,z)]\)这个公式变一下.就是考虑每一个点的贡献,做出贡献的点一定在\(z\)到根节点的 ...
- BZOJ 3626: [LNOI2014]LCA [树链剖分 离线|主席树]
3626: [LNOI2014]LCA Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 2050 Solved: 817[Submit][Status ...
- BZOJ 3626: [LNOI2014]LCA( 树链剖分 + 离线 )
说多了都是泪啊...调了这么久.. 离线可以搞 , 树链剖分就OK了... -------------------------------------------------------------- ...
- BZOJ 3626 [LNOI2014]LCA 树剖+(离线+线段树 // 在线+主席树)
BZOJ 4012 [HNOI2015]开店 的弱化版,离线了,而且没有边权(长度). 两种做法 1 树剖+离线+线段树 这道题求的是一个点zzz与[l,r][l,r][l,r]内所有点的lcalca ...
- BZOJ 3626: [LNOI2014]LCA 树链剖分 线段树 离线
http://www.lydsy.com/JudgeOnline/problem.php?id=3626 LNOI的树链剖分题没有HAOI那么水,学到的东西还是很多的. 我如果现场写,很难想出来这种题 ...
- bzoj 3626 : [LNOI2014]LCA (树链剖分+线段树)
Description 给出一个n个节点的有根树(编号为0到n-1,根节点为0).一个点的深度定义为这个节点到根的距离+1.设dep[i]表示点i的深度,LCA(i,j)表示i与j的最近公共祖先.有q ...
- BZOJ 3626 [LNOI2014]LCA ——树链剖分
思路转化很巧妙. 首先把询问做差分. 然后发现加入一个点就把路径上的点都+1,询问的时候直接询问到根的路径和. 这样和原问题是等价的,然后树链剖分+线段树就可以做了. #include <map ...
- bzoj 3626 [LNOI2014]LCA(离线处理+树链剖分,线段树)
3626: [LNOI2014]LCA Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 1272 Solved: 451[Submit][Status ...
- bzoj 3626: [LNOI2014]LCA 离线+树链剖分
3626: [LNOI2014]LCA Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 426 Solved: 124[Submit][Status] ...
随机推荐
- Jmeter拓展插件(jmeter-plugins)
Jmeter是一款开源的性能测试工具,纯java编写,体积小,功能强大,基本可以满足性能测试需求.另Jmeter还右一系列的插件来增强其功能,插件地址jmeter-plugins.org.插件现在有5 ...
- springboot 中使用AOP
网上关于AOP的例子好多,各种名词解释也一大堆,反正名词各种晦涩,自己写个最最最简单的例子入门mark一下,以后再深入学习. maven依赖 <dependency> <groupI ...
- 《TomCat与Java Web开发技术详解》(第二版) 第六章节的学习总结 ---- JSP技术
第六章主要介绍了JSP的相关知识. 1.JSP:是通过在HTML文件中加入java程序片段(Java Scriptlet)和JSP标记,就构成了JSP文件.JSP实质上是Servlet.JSP的API ...
- UVA 10131题解
第一次写动态规划的代码,整了一天,终于AC. 题目: Question 1: Is Bigger Smarter? The Problem Some people think that the big ...
- rsync客户端命令使用简介
rsync是linux下很流行的增量备份工具,也支持本地文件(夹)复制至远程,而且支持只传输增量部分,也是一个代码(程序)发布的好工具. 基本用法如下: rsync [一堆选项] 源文件(夹) 目标文 ...
- Crashing Robots - poj 2632
Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 8352 Accepted: 3613 Description In ...
- 设计模式之前之UML
UML,让系统可视化,让规格和设计文档化的表现方法.下面来简单介绍一下这个UML.
- Android Studio 2.3版本 Run项目不能自动启动APP的问题 (转)
参考: http://blog.csdn.net/lucasey/article/details/61071377 Android Studio 升级到2.3版本后 运行项目后,只是安装上了,而APP ...
- unity绝对路径与相对路径转化
绝对路径->相对路径 string mp =“H:\unity(project)\New Unity Project\Assets\111.mat”; mp = mp.Substring(mp. ...
- GitHub 小试牛刀(踩坑记录)
首先要在GitHub上创建好远程仓库,把README,LISCENCE,.gitignore三个文件在远程仓库初始化好. 然后在创建本地仓库,先要cd到自己的项目目录下,然后: $ git init ...