BZOJ3626 [LNOI2014]LCA(树链剖分)
来源:互联网 发布:淘宝新疆昆仑雪菊 编辑:程序博客网 时间:2024/05/16 23:35
【题解】
若将0到u路径上所有点标记,则deep[LCA(u,v)]等于从v上溯到的第一个被标记点的deep,而再往上的话一直到根,经过的点都是被标记点
由前缀和的思想,将0到u路径上所有点权值设为1,其他点权值为0,那么deep[LCA(u,v)]等于SUM(0到v路径上的点权和)
再进一步想,deep[LCA(u1,v)]+deep[LCA(u2,v)]怎么求?
1.可以将0到v路径上的点权设为1,再分别求u1,u2到根的点权和,但这样无法优化时间,相当于暴力
2.也可以将0到u1路径上的点权加1,再将0到u2路径上的点权加1,然后求v到根的点权和,因为每个值为1的权相当于深度的一步,是可叠加的
按照方法2,在 将0至ui的路径上的结点权值加1 之后(ui取遍[l,r]),就可以一并求出sigma_{l<=i<=r}dep[LCA(i,z)]了
对于q次询问,不能每次都把点权变来变去,这里再次利用叠加性与前缀和思想,将ans[l,r]拆开,转换为ans[0,r]-ans[0,l-1],求解两个子问题即可
这样,我们可以预处理完1~n-1每个点的影响:每个点到根所经过的点的权值加1,链剖+线段树维护路径点权和
在这个过程中,2*q个被拆开的询问离线处理即可,比如询问ans[0,x]:在处理完点x后,求它到根的路径上的权值和,并记录下这来自第几个问题就行了
本题中的重要思想:区间查询都可以转化为前缀和的差值,还有如何将LCA问题转化为维护树上路径信息的问题
【代码】
#include<stdio.h>#include<stdlib.h>#include<vector>#define MOD 201314using namespace std;typedef long long LL;vector<int> G[50005],A[50005],N[50005];int fa[50005]={0},size[50005]={0},son[50005]={0},top[50005]={0},pos[50005]={0},p[50005]={0};LL sumv[200000]={0},addv[200000]={0},Q[50005][5]={0};int n,e=0,tot=0;LL jdz(LL x){if(x<0) x=-x;return x;}void dfs1(int x){int i;size[x]=1;for(i=0;i<G[x].size();i++){dfs1(G[x][i]);size[x]+=size[G[x][i]];if(son[x]==0||size[son[x]]<size[G[x][i]]) son[x]=G[x][i];}}void dfs2(int x,int t){int i;top[x]=t;pos[x]=++tot;if(son[x]!=0) dfs2(son[x],t);for(i=0;i<G[x].size();i++)if(G[x][i]!=son[x]) dfs2(G[x][i],G[x][i]);}void xg(LL p,int x,int y,int o,int left,int right){int mid=(left+right)/2;if(x<=left&&right<=y) addv[o]+=p;else{if(x<=mid) xg(p,x,y,o*2,left,mid);if(y>mid) xg(p,x,y,o*2+1,mid+1,right);}if(left<right) sumv[o]=sumv[o*2]+sumv[o*2+1]+addv[o]*(LL)(right-left+1);else sumv[o]+=p;}LL cx(int x,int y,int o,int left,int right,LL add){LL ans=0;int mid=(left+right)/2;if(x<=left&&right<=y) return sumv[o]+add*(LL)(right-left+1);add+=addv[o];if(x<=mid) ans+=cx(x,y,o*2,left,mid,add);if(y>mid) ans+=cx(x,y,o*2+1,mid+1,right,add);return ans;}void update(int x){int tx=top[x];while(tx!=0){xg(1,pos[tx],pos[x],1,1,n);x=fa[tx];tx=top[x];}xg(1,pos[0],pos[x],1,1,n);}LL getsum(int x){LL ans=0;int tx=top[x];while(tx!=0){ans=ans+cx(pos[tx],pos[x],1,1,n,0);x=fa[tx];tx=top[x];}return ans+cx(pos[0],pos[x],1,1,n,0);}int main(){int q,i,j,l,r,z;scanf("%d%d",&n,&q);for(i=1;i<n;i++){scanf("%d",&fa[i]);G[fa[i]].push_back(i);}dfs1(0);dfs2(0,0);for(i=1;i<=q;i++){scanf("%d%d%d",&l,&r,&z);if(l>0){A[l-1].push_back(z);N[l-1].push_back(i);}A[r].push_back(z);N[r].push_back(i);}for(i=0;i<n;i++){update(i);for(j=0;j<A[i].size();j++)Q[N[i][j]][++p[N[i][j]]]=getsum(A[i][j]);}for(i=1;i<=q;i++)printf("%lld\n",jdz(Q[i][1]-Q[i][2])%MOD);return 0;}注意最后求答案时Q[i][j]不能是mod过的,否则会导致错误,所以Q[i][j]需定义成long long类型
或者Q[i][j]是mod过的也行,但需要记录这个Q[i][j]属于ans[0,l-1]还是ans[0,r]
0 0
- BZOJ3626 [LNOI2014]LCA(树链剖分)
- [BZOJ3626][LNOI2014]LCA 树链剖分
- bzoj3626[LNOI2014]LCA 树链剖分
- [bzoj3626][LNOI2014]LCA 树链剖分
- [BZOJ3626][LNOI2014]LCA(离线+差分+树链剖分)
- bzoj3626: [LNOI2014]LCA (树链剖分+离线线段树)
- [BZOJ3626][LNOI2014]LCA(离线+链剖)
- 【BZOJ3626】 [LNOI2014]LCA
- BZOJ3626: [LNOI2014]LCA
- bzoj3626【LNOI2014】LCA
- [BZOJ3626] [LNOI2014]LCA
- BZOJ3626: [LNOI2014]LCA
- [bzoj3626][LNOI2014]LCA
- [LNOI2014][BZOJ3626]LCA
- BZOJ3626 [LNOI2014]LCA
- bzoj3626[LNOI2014] LCA
- BZOJ3626: [LNOI2014]LCA LCT
- 【LNOI2014】bzoj3626 LCA
- Spring框架依赖注入的一个简单应用
- mysql数据库应用(三)----数据库的存储引擎
- android开发之android的平台架构及特性
- UVA 437 The Tower of Babylon (DAG上的无源最长路 or LIS)
- 1030_完美数列(25)
- BZOJ3626 [LNOI2014]LCA(树链剖分)
- Integrated Change Control – Sequence of Change Request
- “贵”是一个招牌
- cf Round #239 (Div. 1) B. Long Path
- 优先队列优化的dijsktra
- c语言中功能键和箭头使用
- [LeetCode] Best Time to Buy and Sell Stock
- 串口线的种类
- UVa 116 - Unidirectional TSP(单向TSP)