BZOJ 3626: [LNOI2014]LCA(树链剖分+离线处理)
3626: [LNOI2014] LCA
Time Limit: 10 Sec
Memory Limit: 128 MBDescription###
给出一个n个节点的有根树(编号为0到n-1,根节点为0)。一个点的深度定义为这个点到根的距离+1。设dep[i]表示点i的深度,LCA(i,j)表示i与j的最近公共祖先。有q次询问,每次询问给出l r z,求 sigma_{l<=i<=r}dep[LCA(i,z)]。(即求在[l,r]区间内的每个节点i与z的最近公共祖先的深度之和)
Input###
第一行2个整数n q。
接下来n-1行,分别表示点1到点n-1的父节点编号。
接下来q行,每行3个整数l r z。
Output###
输出q行,每行表示一个询问的答案。每个答案对201314取模输出
Sample Input 1###
5 2
0
0
1
1
1 4 3
1 4 2
Sample Output 1###
8
5HINT###
共5组数据,n与q的规模分别为10000,20000,30000,40000,50000。
题目地址: BZOJ 3626: [LNOI2014]LCA
题解:
从最简单的求lca(u,v)的方法想起
即把u到根的路径上的点都标记,v也向父亲跳,跳到第一个带标记的点即为lca
若把标记改为点权加一,发现lca的深度即为v到根的路径上的点权和
对于本题,把l~r的每个点到根的路径上的点都加一,点z到根的路径的点权和即为所求
到这里都可用树剖解决,但显然会超时
把[l,r]分成[1,l-1]和[1,r]来做
然后离线处理,从1到n一次加点权
复杂度O((n+q)lognlogn)
www.cnblogs.com/AGFghy/
AC代码
#include<cstdio>
#include<algorithm>
using namespace std;
typedef long long ll;
const int N=5e4+5;
struct prob
{
int e,id,pd,nd;
}q[N<<1];
struct Tree
{
int v,lazy;
}tree[N<<2];
int n,Q,mo,num,cnt,now,nf,z;
int point[N],next[N],head[N];
int fa[N],dep[N],size[N],son[N],top[N],id[N];
int ans1[N],ans2[N];
bool cmp(prob q1,prob q2)
{
return q1.e<q2.e;
}
void add(int u,int v)
{
point[++num]=v;
next[num]=head[u];
head[u]=num;
}
void dfs1(int now,int pre)
{
fa[now]=pre;
dep[now]=dep[pre]+1;
size[now]=1;
for (int i=head[now]; i; i=next[i])
{
int v=point[i];
if (v==pre) continue;
dfs1(v,now);
size[now]+=size[v];
if (size[v]>size[son[now]]) son[now]=v;
}
}
void dfs2(int now,int topf)
{
top[now]=topf;
id[now]=++cnt;
if (!son[now]) return;
dfs2(son[now],topf);
for (int i=head[now]; i; i=next[i])
{
int v=point[i];
if (v==fa[now] || v==son[now]) continue;
dfs2(v,v);
}
}
void pushup(int p)
{
tree[p].v=(tree[p<<1].v+tree[(p<<1)+1].v)%mo;
}
void pushdown(int p,int l,int r)
{
if (tree[p].lazy)
{
int mid=(l+r)>>1;
tree[p<<1].lazy+=tree[p].lazy;
tree[(p<<1)+1].lazy+=tree[p].lazy;
tree[p<<1].v=(tree[p<<1].v+((ll)(mid-l+1)*tree[p].lazy)%mo)%mo;
tree[(p<<1)+1].v=(tree[(p<<1)+1].v+((ll)(r-mid)*tree[p].lazy)%mo)%mo;
tree[p].lazy=0;
}
}
void update(int l,int r,int p,int s,int t)
{
if (l==s && r==t)
{
tree[p].v=(tree[p].v+r-l+1)%mo;
tree[p].lazy++;
return;
}
pushdown(p,l,r);
int mid=(l+r)>>1;
if (t<=mid) update(l,mid,p<<1,s,t);
else if (s>mid) update(mid+1,r,(p<<1)+1,s,t);
else
{
update(l,mid,p<<1,s,mid);
update(mid+1,r,(p<<1)+1,mid+1,t);
}
pushup(p);
}
int query(int l,int r,int p,int s,int t)
{
if (l==s && r==t) return tree[p].v;
pushdown(p,l,r);
int mid=(l+r)>>1;
if (t<=mid) return query(l,mid,p<<1,s,t);
else if (s>mid) return query(mid+1,r,(p<<1)+1,s,t);
else return (query(l,mid,p<<1,s,mid)+query(mid+1,r,(p<<1)+1,mid+1,t))%mo;
}
void modify(int x,int y)
{
while (top[x]!=top[y])
{
if (dep[top[x]]<dep[top[y]]) swap(x,y);
update(1,n,1,id[top[x]],id[x]);
x=fa[top[x]];
}
if (dep[x]>dep[y]) swap(x,y);
update(1,n,1,id[x],id[y]);
}
int getans(int x,int y)
{
int res=0;
while (top[x]!=top[y])
{
if (dep[top[x]]<dep[top[y]]) swap(x,y);
res=(res+query(1,n,1,id[top[x]],id[x]))%mo;
x=fa[top[x]];
}
if (dep[x]>dep[y]) swap(x,y);
res=(res+query(1,n,1,id[x],id[y]))%mo;
return res;
}
int main()
{
mo=201314;
scanf("%d%d",&n,&Q);
for (int i=1; i<=n-1; i++)
{
scanf("%d",&nf);
nf++;
add(nf,i+1);
}
dfs1(1,0);
dfs2(1,1);
for (int i=1; i<=Q; i++)
{
scanf("%d%d%d",&q[i].e,&q[i+Q].e,&z);
q[i+Q].e++; z++;
q[i].nd=q[i+Q].nd=z;
q[i].id=q[i+Q].id=i;
q[i+Q].pd=1;
}
sort(q+1,q+2*Q+1,cmp);
now=1;
while (q[now].e==0) now++;
for (int i=1; i<=n; i++)
{
modify(1,i);
while (q[now].e==i)
{
if (q[now].pd==0) ans1[q[now].id]=getans(1,q[now].nd);
else ans2[q[now].id]=getans(1,q[now].nd);
now++;
}
}
for (int i=1; i<=Q; i++)
printf("%d\n",(((ans2[i]-ans1[i])%mo)+mo)%mo);
}