【题解 P4211】 LCA

[LNOI2014] LCA

题目描述

给出一个 \(n\) 个节点的有根树(编号为 \(0\)\(n-1\),根节点为 \(0\) )。

一个点的深度定义为这个节点到根的距离 \(+1\)

\(dep[i]\) 表示点 \(i\) 的深度,\(\operatorname{LCA}(i, j)\) 表示 \(i\)\(j\) 的最近公共祖先。

\(m\) 次询问,每次询问给出 \(l, r, z\),求 \(\sum_{i=l}^r dep[\operatorname{LCA}(i,z)]\)

输入格式

第一行 \(2\) 个整数,\(n, m\)

接下来 \(n-1\) 行,分别表示点 \(1\) 到点 \(n-1\) 的父节点编号。

接下来 \(m\) 行,每行 \(3\) 个整数,\(l, r, z\)

输出格式

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

样例 #1

样例输入 #1

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

样例输出 #1

8
5

提示

对于 \(20\%\) 的数据,\(n\le 10000,m\le 10000\)

对于 \(40\%\) 的数据,\(n\le 20000,m\le 20000\)

对于 \(60\%\) 的数据,\(n\le 30000,m\le 30000\)

对于 \(80\%\) 的数据,\(n\le 40000,m\le 40000\)

对于 \(100\%\) 的数据,\(1\le n\le 50000,1\le m\le 50000\)

解题思路

一个点的深度还可以看成什么?还可以看成是这个点到根节点的点数。
那么,求 $\sum_{i=l}^r dep[\operatorname{LCA}(i,z)] $ ,相当于求对于每一个 \(l\le i \le r\)\(\operatorname{LCA}(i,z)\) 到根节点的点数。
由于都有一个 \(z\) ,我们可以看成 \(i\) 到根节点的路径与 \(z\) 到根节点共同的点数。
那我们可以把 \([l,r]\) 之间的每个数到根节点的路径上的点权都加上 \(1\) ,然后再求出 \(z\) 到根节点的点权和即可。
进一步优化,我们把每个问题区间拆成 \([1,l-1]\)\([1,r]\) 两部分,每次只需将 \([1,x]\) 到根节点的路径上的点权值 \(+1\)
这些区间是有共同部分的,我们只需按右端点从小到大排序,每次加上后继续做下一个即可。
时间复杂度 \(O(mlog^2n)\)

Code

#include<bits/stdc++.h>
using namespace std;
long long mod=201314;
struct datay
{
	long long x,y,p,v;
}l[100005];
long long n,m,son[50005],size[50005],fa[50005],deep[50005],q;
long long dfn[50005],top[50005],num;
long long f[200005],d[200005];
vector<long long> a[50005];
bool cmp(datay qw,datay er)
{
	return qw.x<er.x;
}
bool cmp1(datay qw,datay er)
{
	return qw.p<er.p;
}
void dfs1(long long x,long long y)
{
	fa[x]=y;
	deep[x]=deep[y]+1;
	size[x]=1;
	for(int i=0;i<a[x].size();i++)
	{
		if(a[x][i]==y)continue;
		dfs1(a[x][i],x);
		size[x]+=size[a[x][i]];
		if(size[a[x][i]>size[son[x]]])son[x]=a[x][i]; 
	}
	return;
}
void dfs2(long long x,long long y)
{
	dfn[x]=++num;
	if(son[x])
	{
		top[son[x]]=top[x];
		dfs2(son[x],x);
	}
	for(int i=0;i<a[x].size();i++)
	{
		if(a[x][i]==y||a[x][i]==son[x])continue;
		top[a[x][i]]=a[x][i];
		dfs2(a[x][i],x);
	}
	return;
}
void galaxy(long long x,long long l,long long r,long long v)
{
	f[x]+=v*(r-l+1);
	d[x]+=v;
	return;
}
void up(long long x)
{
	f[x]=f[x<<1]+f[(x<<1)|1];
	return;
}
void pushdown(long long x,long long l,long long r)
{
	if(d[x]==0)return;
	long long lc=(x<<1),rc=(x<<1)|1,mid=(l+r)>>1;
	galaxy(lc,l,mid,d[x]);
	galaxy(rc,mid+1,r,d[x]);
	d[x]=0;
	return;
}
void dijah(long long x,long long l,long long r,long long ql,long long qr,long long v)
{
	if(ql<=l&&r<=qr)
	{
		galaxy(x,l,r,v);
		return;
	}
	pushdown(x,l,r);
	long long lc=(x<<1),rc=(x<<1)|1,mid=(l+r)>>1;
	if(ql<=mid)dijah(lc,l,mid,ql,qr,v);
	if(qr>mid)dijah(rc,mid+1,r,ql,qr,v);
	up(x); 
	return;
}
long long gaia(long long x,long long l,long long r,long long ql,long long qr)
{
	if(ql<=l&&r<=qr)return f[x];
	pushdown(x,l,r);
	long long lc=(x<<1),rc=(x<<1)|1,mid=(l+r)>>1,h=0;
	if(ql<=mid)h+=gaia(lc,l,mid,ql,qr);
	if(qr>mid)h+=gaia(rc,mid+1,r,ql,qr);
	return h;
}
void add(long long x,long long y,long long v)
{
	while(top[x]!=top[y])
	{
		if(deep[top[x]]<deep[top[y]])swap(x,y);
		dijah(1,1,n,dfn[top[x]],dfn[x],v);
		x=top[x];
		x=fa[x];
	}
	if(deep[x]>deep[y])swap(x,y);
	dijah(1,1,n,dfn[x],dfn[y],v);
}
long long gaia(long long x,long long y)
{
	long long h=0;
	while(top[x]!=top[y])
	{
		if(deep[top[x]]<deep[top[y]])swap(x,y);
		h+=gaia(1,1,n,dfn[top[x]],dfn[x]);
		x=top[x];
		x=fa[x];
	}
	if(deep[x]>deep[y])swap(x,y);
	h+=gaia(1,1,n,dfn[x],dfn[y]);
	return h;
}
int main()
{
	long long x,y,z;
	scanf("%lld%lld",&n,&m);
	for(int i=2;i<=n;i++)
	{
		scanf("%lld",&x);
		x++;
		a[i].push_back(x);
		a[x].push_back(i);
	}
	dfs1(1,0);
	top[1]=1;
	dfs2(1,0);
	for(int i=1;i<=m;i++)
	{
		scanf("%lld%lld%lld",&x,&y,&z);
		x++;
		y++;
		z++;
		if(x>y)swap(x,y);
		l[++q].x=x-1;
		l[q].y=z;
		l[q].p=2*i-1;
		l[++q].x=y;
		l[q].y=z;
		l[q].p=2*i;
	}
	sort(l+1,l+q+1,cmp);
	for(int i=1;i<=q;i++)
	{
		if(l[i].x==0)continue;
		for(int j=l[i-1].x+1;j<=l[i].x;j++)add(1,j,1);
		l[i].v=gaia(l[i].y,1);
	}
	sort(l+1,l+q+1,cmp1);
	for(int i=1;i<=q;i+=2)
	{
		cout<<((l[i+1].v-l[i].v)%mod+mod)%mod<<'\n';
	}








  return 0;
}

posted @ 2023-11-13 21:26  dijah  阅读(16)  评论(0编辑  收藏  举报