BZOJ 3626: [LNOI2014]LCA(树链剖分+离线处理)


3626: [LNOI2014] LCA

  Time Limit: 10 Sec
  Memory Limit: 128 MB

Description###

  给出一个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
  5

HINT###

  共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);
}
posted @ 2018-07-24 21:13  AGFghy  阅读(198)  评论(0编辑  收藏  举报