【做题记录】P4211 [LNOI2014]LCA


P4211 [LNOI2014]LCA

题意

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

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

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

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

题解

我们考虑这样一件事情,就是说,两个点的 \(Lca\) 的深度的意义到底是什么,如何才能够快速求的?

在我们不会求 \(Lca\) 的时候,我们会将一个点一个一个往上爬,并将路径上的点染色。之后我们将另一个点暴力往上跳,第一个染色过的点就是 \(Lca\)

我们考虑到这样一件事情,如果我们将一个点到根的路径上每个点数值加 \(1\),再求得另一个点到根的路径上的权值和,这不就是 \(Lca\) 的深度了吗?

于是求解一次询问就相当于对于 \(l\le x\le r\),将 \(x\) 到根的路径上每个点加一,最后答案就是 \(z\) 到根的权值和。

由于询问次数很多,不可能每次都这样处理一遍,考虑将询问拆开。

\[\sum_{i=l}^r dep[LCA(i,z)]=\sum_{i=1}^r dep[LCA(i,z)]-\sum_{i=1}^{l-1} dep[LCA(i,z)] \]

这样我们就可以在 \(O(n\log n)\) 复杂度内解决问题啦!

这就叫数据结构二步曲,学习一下,代码我现在放下。

#define Maxn 50005
#define pb push_back
#define mod 201314
typedef long long ll;
int n,m,tot,Time,cnt;
int ans[Maxn];
int dfn[Maxn],tp[Maxn],fa[Maxn],dep[Maxn],siz[Maxn],bigson[Maxn];
int hea[Maxn],nex[Maxn],ver[Maxn];
struct TREE { int laz,sum; }tree[Maxn<<2];
struct Query { int num,z,opt; };
vector q[Maxn];
void dfs1(int x)
{
	 siz[x]=1;
	 for(int i=hea[x];i;i=nex[i])
	 {
	 	 fa[ver[i]]=x,dep[ver[i]]=dep[x]+1;
	 	 dfs1(ver[i]),siz[x]+=siz[ver[i]];
	 	 if(siz[ver[i]]>siz[bigson[x]]) bigson[x]=ver[i];
	 }
}
void dfs2(int x,int T)
{
	 tp[x]=T,dfn[x]=++Time;
	 if(bigson[x]) dfs2(bigson[x],T);
	 for(int i=hea[x];i;i=nex[i])
	 {
	 	 if(ver[i]==bigson[x]) continue;
	 	 dfs2(ver[i],ver[i]);
	 }
}
void pushdown(int p,int nl,int nr)
{
	 int mid=(nl+nr)>>1;
	 tree[p<<1].laz=(tree[p<<1].laz+tree[p].laz)%mod;
	 tree[p<<1|1].laz=(tree[p<<1|1].laz+tree[p].laz)%mod;
	 tree[p<<1].sum=(tree[p<<1].sum+1ll*tree[p].laz*(mid-nl+1)%mod)%mod;
	 tree[p<<1|1].sum=(tree[p<<1|1].sum+1ll*tree[p].laz*(nr-mid)%mod)%mod;
	 tree[p].laz=0;
}
void add(int p,int nl,int nr,int l,int r)
{
	 if(nl>=l && nr<=r) { tree[p].laz++,tree[p].sum+=(nr-nl+1); return; }
	 pushdown(p,nl,nr);
	 int mid=(nl+nr)>>1;
	 if(mid>=l) add(p<<1,nl,mid,l,r);
	 if(mid=l && nr<=r) return tree[p].sum;
	 pushdown(p,nl,nr);
	 int mid=(nl+nr)>>1,ret=0;
	 if(mid>=l) ret=(ret+query(p<<1,nl,mid,l,r))%mod;
	 if(mid