zoukankan      html  css  js  c++  java
  • 【BZOJ-3626】LCA 树链剖分

    3626: [LNOI2014]LCA

    Time Limit: 10 Sec  Memory Limit: 128 MB
    Submit: 1428  Solved: 526
    [Submit][Status][Discuss]

    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

    5 2
    0
    0
    1
    1
    1 4 3
    1 4 2

    Sample Output

    8
    5

    HINT

    共5组数据,n与q的规模分别为10000,20000,30000,40000,50000。

    Source

    数据已加强 by saffah

    Solution

    先是两篇高端的题解:HZW学长  TimeMachine学长

    什么LCA,都是骗人的

    直接暴力去做,很显然不可以,那么这必然会有一些性质或者转化使之简便

    那么考虑一种其他的做法

    离线处理,把每个询问拆成两个部分,分别是【1~l-1】和【1~r】那么前缀和?

    那么维护一下信息,即z点到根的路径

    然后加每个点的时候是把从这个点到根的路径的点权全部+1,然后查询就是查询某个点到根的路径的点权和

    Code

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cmath>
    #include<cstring>
    using namespace std;
    int read()
    {
        int x=0,f=1; char ch=getchar();
        while (ch<'0' || ch>'9') {if (ch=='-') f=-1; ch=getchar();}
        while (ch>='0' && ch<='9') {x=x*10+ch-'0'; ch=getchar();}
        return x*f;
    }
    #define mod 201314
    #define maxn 100100
    #define maxq 100100
    struct Edgenode{int to,next;}edge[maxn];
    int head[maxn],cnt;int n,q,zz;
    void add(int u,int v)
    {cnt++;edge[cnt].to=v;edge[cnt].next=head[u];head[u]=cnt;}
    //
    int size[maxn],pre[maxn],deep[maxn],son[maxn],fa[maxn],pl[maxn],sz,pr[maxn],top[maxn];
    void dfs_1(int x)
    {
        size[x]=1;
        for(int i=head[x];i;i=edge[i].next)
            if (edge[i].to!=fa[x])
                {
                    deep[edge[i].to]=deep[x]+1;
                    fa[edge[i].to]=x;
                    dfs_1(edge[i].to);
                    size[x]+=size[edge[i].to];
                }
    }
    void dfs_2(int x,int chain)
    {
        top[x]=chain; pl[x]=++sz;
        int k=n;
        for(int i=head[x];i;i=edge[i].next)
            if(edge[i].to!=fa[x]&&size[edge[i].to]>size[k])
                k=edge[i].to;
        if(k!=n) dfs_2(k,chain);
        for(int i=head[x];i;i=edge[i].next)
            if(edge[i].to!=fa[x]&&edge[i].to!=k)
                dfs_2(edge[i].to,edge[i].to);
    }
    //
    struct Treenode{int l,r,tag,da;}tree[maxn<<2];
    inline void update(int now)
    {tree[now].da=tree[now<<1].da+tree[now<<1|1].da;}
    inline void pushdown(int now)
    {
        int l=tree[now].l,r=tree[now].r,tag=tree[now].tag;    
        int mid=(l+r)>>1,ln=mid-l+1,rn=r-mid;
        if (tag)
            {
                tree[now].tag=0;
                tree[now<<1].tag+=tag; tree[now<<1|1].tag+=tag;
                tree[now<<1].da+=ln*tag; tree[now<<1|1].da+=rn*tag;
            }
    }
    void build(int now,int l,int r)
    {
        tree[now].tag=tree[now].da=0;
        tree[now].l=l;tree[now].r=r;
        if (l==r) return;
        int mid=(l+r)>>1;
        build(now<<1,l,mid); build(now<<1|1,mid+1,r);
    }
    void segment_change(int now,int L,int R)
    {
        pushdown(now);
        if (L<=tree[now].l && R>=tree[now].r) 
            {tree[now].da+=(tree[now].r-tree[now].l+1);tree[now].tag++;return;}
        int mid=(tree[now].l+tree[now].r)>>1;
        if (L<=mid) segment_change(now<<1,L,R);
        if (R>mid) segment_change(now<<1|1,L,R);
        update(now);
    }
    int segment_ask(int now,int L,int R)
    {
        pushdown(now);
        if (L<=tree[now].l && R>=tree[now].r) return tree[now].da;
        int mid=(tree[now].l+tree[now].r)>>1; int ans=0;
        if (L<=mid) ans+=segment_ask(now<<1,L,R);
        if (R>mid) ans+=segment_ask(now<<1|1,L,R);
        return ans;
    }
    
    //
    void change(int x,int y)
    {
        while (top[x]!=top[y])
            {
                segment_change(1,pl[top[x]],pl[x]);
                x=fa[top[x]];
            }
        segment_change(1,pl[y],pl[x]);
    }
    int query(int x,int y)
    {
        int ans=0;
        while (top[x]!=top[y])
            {
                ans=(ans+segment_ask(1,pl[top[x]],pl[x]))%mod;
                x=fa[top[x]];            
            }
        ans=(ans+segment_ask(1,pl[y],pl[x]))%mod;
        return ans;
    }
    //
    struct Asknode{int z,ans1,ans2;}ask[maxq];
    struct Reqnode
    {
        int p,id;bool f;
        bool operator < (const Reqnode & A) const
            {return p<A.p;}
    }req[maxq<<1];
    int main()
    {
    //    freopen("3626.in","r",stdin);
    //    freopen("3626.out","w",stdout);
        n=read(),q=read();
        for (int x,i=1; i<=n-1; i++)
            x=read(),add(x,i);
        for (int a,b,c,i=1; i<=q; i++)
            {
                a=read(),b=read(),c=read();
                ask[i].z=c;
                zz++;req[zz].p=a-1;req[zz].id=i;req[zz].f=0;
                zz++;req[zz].p=b;req[zz].id=i;req[zz].f=1;
            }
        sort(req+1,req+zz+1);
    //    for (int i=1; i<=zz; i++)
    //        printf("%d %d %d
    ",req[i].p,req[i].id,req[i].f);
        build(1,1,n); dfs_1(0); dfs_2(0,0);
    //    for (int i=0; i<=n; i++)
    //        printf("%d %d %d %d %d %d
    ",i,fa[i],deep[i],pl[i],size[i],top[i]);
        int now=-1;
        for (int i=1; i<=zz; i++)
            {
                while (now<req[i].p)
                    now++,change(now,0);
    //            printf("%d
    ",query(ask[req[i].id].z,0));
                if (!req[i].f) ask[req[i].id].ans1=query(ask[req[i].id].z,0);
                else ask[req[i].id].ans2=query(ask[req[i].id].z,0);
            }
        for (int i=1; i<=q; i++)
            printf("%d
    ",(ask[i].ans2-ask[i].ans1+mod)%mod);
        return 0;
    }

    sb错误毁一生!!!!

    数据生成器:

    #include<cstdio>
    #include<ctime>
    #include<cstdlib>
    using namespace std;
    int main()
    {
        freopen("3626.in","w",stdout);
        int n;
        srand(time(0));
    //    scanf("%d",&n);
        n=40000;
        printf("%d %d
    ",n,n);
        for (int i=0;i<=n-2;i++)
            printf("%d
    ",rand()%(i+1));
        for (int i=1;i<=n;i++)
            printf("%d %d %d
    ",rand()%n,rand()%n,rand()%n);
        return 0;
    }
  • 相关阅读:
    twitter分享问题(三)——Required oauth_verifier parameter not provided
    旋转数组的最小数字
    关系型数据库基础之:简单的数据查询
    twitter分享问题(一)——MISSING_ARG_APIKEY
    extern "C"的理解
    从一个链接错误探究GCC的链接库顺序
    GAE 博客——B3log Solo 0.4.0 正式版发布了!
    不使用资源文件动态创建对话框的做法
    GAE 博客——B3log Solo 0.4.0 正式版发布了!
    CodeBlocks启动多个进程实例的做法
  • 原文地址:https://www.cnblogs.com/DaD3zZ-Beyonder/p/5356773.html
Copyright © 2011-2022 走看看