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] ...
随机推荐
- C++编译错误C2365
曾经我们说重定义一般是函数或者变量的重定义.今天遇到了一个新类型的重定义errorC2365 #include <iostream> using namespace std; class ...
- 玩转JPA(一)---异常:Repeated column in mapping for entity/should be mapped with insert="false" update="fal
近期用JPA遇到这样一个问题:Repeated column in mapping for entity: com.ketayao.security.entity.main.User column: ...
- How can I detect multiple logins into a Django web application from different locations?
1) Install django-tracking (thankyou for that tip Van Gale Google Maps + GeoIP is amazing!) 2) Add t ...
- Linux中crontab下scp文件传输的两种方式
Linux下文件传输一般有两个命令scp.ftp(工具需要下载安装) 本文主要讲讲scp的文件传输脚本 1.scp ssh-keygen -t rsa免输入密码,传输 这里假设主机A 用来获到主机B的 ...
- Angular1.0 在Directive中调用Controller的方法
Controller中定义了$scope.method = function(){} Directive中需要引入$scope http://stackoverflow.com/questions/2 ...
- 微信小程序事件
微信小程序事件1.什么是事件2.事件类别3.事件冒泡4.事件绑定5.事件对象详解笔记:1.事件是一种用户的行为,是一种通讯方式.2.事件类别: 点击事件:tap 长按事件:longtap ...
- Miller-Rabin大素数测试模板
根据费马小定理: 对于素数n,a(0<a<n),a^(n-1)=1(mod n) 如果对于一个<n的正整数a,a^(n-1)!=1(mod n),则n必不是素数. 然后就可以随机生成 ...
- eclipse 创建maven web 项目
虽然网上教程一大把,但也重新整理下. 一.创建项目 1.Eclipse中用Maven创建项目 上图中Next 2.继续Next 3.选maven-archetype-webapp后,next 4.填写 ...
- python高级语法进阶
python中几个比较难懂概念进阶. 迭代器 实现了迭代器协议的容器对象,基于如下两个方法: __next__:返回容器的下一个元素 __iter__:返回迭代器本身 由此可见,如果要自定义一个迭代器 ...
- nodejs windows下安装运行
node 官网下载地址http://nodejs.org/ 下载自己对应的版本 ,我下的是windows版本 node-v4.1.1-x64.msi 然后 下一步 下一步 就完成安装了,非常简单, ...