zoukankan      html  css  js  c++  java
  • 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
    ",(((ans2[i]-ans1[i])%mo)+mo)%mo);
    }
    
  • 相关阅读:
    [转]Xml Schema
    设计模式之Observer Pattern
    通过 C# 使用 J# 类库中的 Zip 类压缩文件
    An extender can't be in a different UpdatePanel than the control it extends
    关于AutoResetEvent和ManualResetEvent
    ref, out参数区别
    取整, 无条件进位, 无条件取整
    VB.NET语法基础
    XP防火墙,挡掉访问自己的IIS
    maybe useful for Add the solution to source control
  • 原文地址:https://www.cnblogs.com/AGFghy/p/9362640.html
Copyright © 2011-2022 走看看