BZOJ3626 [LNOI2014]LCA

BZOJ3626 [LNOI2014]LCA


题目描述

传送门

题目分析

可以考虑不计时间复杂度怎么做,求出所有\(LCA\)然后暴力求和。

那么可以发现这个过程应该是具有可优化性。

一次性求出所有的\(LCA\)显然不大现实,但是可以发现,我们可能求出的\(LCA\)都在根到\(z\)这个节点的路径上。

可以考虑把根到\(z\)的路径的权\(+1\),这样我们的单独看每次操作就等价于求\(\sum_{l\le i\le r}sum(root->i)\)

可以发现,这个操作就等价于把所有\(l->r\)之间的节点到根的路径都\(+1\)后,求出的从\(z\)到根节点的路径和。

可以发现这个操作具有可加性和可减性。

考虑离线处理问题,对所有位置的操作排序之后,利用差分求出所有询问的结果。

可以先从0号节点开始插入,然后即时查询。

即要求的就是\(sum[r]-sum[l-1]\)

可以发现需要维护的是树上的链加和链求和,可以用树链剖分维护。

是代码呢

#include <bits/stdc++.h>
using namespace std;
#define ls (rt<<1)
#define rs (rt<<1|1)
#define mid ((l+r)>>1)
const int MAXN=1e5+7;
const int mo=201314;
int f[MAXN],id[MAXN],w[MAXN],at[MAXN],top[MAXN],dep[MAXN],wson[MAXN],size[MAXN],cnt,tot,add[MAXN<<2],sum[MAXN<<2],n,m;
vector<int> edge[MAXN];
struct Q{
	int pos,id,fl,z;
	bool operator <(const Q &rhs)const{
		return pos<rhs.pos;
	}
}a[MAXN];
struct Ans{
	int l,r;
}s[MAXN];
inline int read()
{
    int x=0,c=1;
    char ch=' ';
    while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
    while(ch=='-')c*=-1,ch=getchar();
    while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
    return x*c;
}
inline void dfs(int u,int fa)
{
	size[u]=1;dep[u]=dep[fa]+1;f[u]=fa;
	for(int i=0;i<edge[u].size();i++){
		int v=edge[u][i];
		if(v==fa) continue;
		dfs(v,u);
		size[u]+=size[v];
		if(size[wson[u]]<size[v]) wson[u]=v;
	}
}
inline void dfs2(int u,int tp)
{
	id[u]=++cnt;top[u]=tp;
	if(wson[u]) dfs2(wson[u],tp);
	for(int i=0;i<edge[u].size();i++){
		int v=edge[u][i];
		if(v==f[u]||v==wson[u]) continue;
		dfs2(v,v);
	}
}
inline void pushdown(int l,int r,int rt)
{
	if(add[rt]){
		(add[ls]+=add[rt])%=mo;(add[rs]+=add[rt])%=mo;
		(sum[ls]+=(mid-l+1)*add[rt])%=mo;(sum[rs]+=(r-mid)*add[rt])%=mo;
		add[rt]=0;
	}
}
inline void update(int L,int R,int l,int r,int rt)
{
	if(L<=l&&r<=R){
		add[rt]+=1;
		(sum[rt]+=r-l+1)%=mo;
		return;
	}
	pushdown(l,r,rt);
	if(L<=mid) update(L,R,l,mid,ls);
	if(R>mid) update(L,R,mid+1,r,rs);
	sum[rt]=sum[ls]+sum[rs];
}
inline int query(int L,int R,int l,int r,int rt)
{
	if(L<=l&&r<=R) return sum[rt];
	pushdown(l,r,rt);
	int ans=0;
	if(L<=mid) ans+=query(L,R,l,mid,ls);
	if(R>mid) ans+=query(L,R,mid+1,r,rs);
	return ans;
}
inline void Update(int x,int y)
{
	while(top[x]!=top[y]){
		if(dep[top[x]]<dep[top[y]]) swap(x,y);
		update(id[top[x]],id[x],1,n,1);
		x=f[top[x]];
	}
	if(dep[x]>dep[y]) swap(x,y);
	update(id[x],id[y],1,n,1);
}
inline int Query(int x,int y)
{
	int ans=0;
	while(top[x]!=top[y]){
		if(dep[top[x]]<dep[top[y]]) swap(x,y);
		(ans+=query(id[top[x]],id[x],1,n,1))%=mo;
		x=f[top[x]];
	}
	if(dep[x]>dep[y]) swap(x,y);
	ans+=query(id[x],id[y],1,n,1);
	return ans%mo;
}
int main()
{
	n=read();m=read();
	for(int i=2;i<=n;i++){
		int x=read()+1;
		edge[i].push_back(x);
		edge[x].push_back(i);
	}
	dfs(1,0);dfs2(1,1);
	for(int i=1;i<=m;i++){
		int x=read(),y=read()+1,z=read()+1;
		a[++tot]=(Q){x,i,0,z};
		a[++tot]=(Q){y,i,1,z};
	}
	sort(a+1,a+tot+1);
	int now=0;
	for(int i=1;i<=tot;i++){
		while(now<a[i].pos){now++;Update(now,1);}
		if(!a[i].fl) s[a[i].id].l=Query(a[i].z,1);
		else s[a[i].id].r=Query(a[i].z,1);
	}
	for(int i=1;i<=m;i++){
		printf("%d\n", ((s[i].r-s[i].l)%mo+mo)%mo);
	}
}
posted @ 2019-01-09 09:23  ~victorique~  阅读(98)  评论(0编辑  收藏  举报
Live2D