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);
}
}
对于作者转载文章,欢迎继续转载。
对于作者原创文章,请注明出处之后转载。