zoukankan      html  css  js  c++  java
  • LNOI2014LCA(树链剖分+离线操作+前缀和)

    题意:给一棵有根树,有多组询问,询问为l r z,求下标为l到r之间的点和z的lca的深度和。

    如果我们一个一个求。emmmmm...

    考虑答案怎么产生,仔细想一想,如果我们把l到r的所有点到根都加上1,那么z到根的和就是答案。

    但这样复杂度还是爆炸,考虑如何优化?

    有一个非常有用的东西,每次操作的下标是连续的!!

    我们此时自然而然的想到前缀和,ans[i]=dis[r]-dis[l-1]。

    那我们从1-n每个点都加一次,遇到操作就加上就好了,复杂度q*log2(n)。

    Code

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<vector>
    #define mod 201314 
    #define N 50009
    using namespace std;
    vector<int>vec[N];
    int head[N],fa[N],tot1,tot,size[N],dfn[N],son[N],top[N],top2,n,qu,ans[N];
    struct ed
    {
        int n,to;
    }an[N];
    struct scd
    {
        int a,id,tag,wo;
    }ins[N<<1];
    struct tree
    {
        int la,num;
    }tr[N<<2];
    inline void add(int u,int v)
    {
        an[++tot1].n=head[u];
        an[tot1].to=v;
        head[u]=tot1;
    }
    void dfs(int u,int f)
    {
        fa[u]=f;
        size[u]=1;
        for(int i=head[u];i;i=an[i].n)
        if(an[i].to!=f)
        {
            int v=an[i].to;
            dfs(v,u);
            size[u]+=size[v];
            if(size[son[u]]<size[v])son[u]=v;
        }
    }
    void dfs2(int u)
    {
        dfn[u]=++top2;
        if(!top[u])top[u]=u;
        if(son[u])top[son[u]]=top[u],dfs2(son[u]);
        for(int i=head[u];i;i=an[i].n)
        if(an[i].to!=fa[u]&&an[i].to!=son[u])dfs2(an[i].to);
    }
    inline void pushdown(int cnt,int l1,int l2)
    {
        (tr[cnt<<1].num+=tr[cnt].la*l1)%=mod;
        (tr[cnt<<1|1].num+=tr[cnt].la*l2)%=mod;
        tr[cnt<<1].la+=tr[cnt].la;
        tr[cnt<<1|1].la+=tr[cnt].la;
        tr[cnt].la=0; 
    }
    void dd(int cnt,int l,int r,int L,int R)
    {
        if(l>=L&&r<=R)
        {
            (tr[cnt].num+=r-l+1)%=mod;
             tr[cnt].la++;
            return;
        }
        int mid=(l+r)>>1;
        if(tr[cnt].la)pushdown(cnt,mid-l+1,r-mid);
        if(mid>=L)dd(cnt<<1,l,mid,L,R);
        if(mid<R)dd(cnt<<1|1,mid+1,r,L,R);
        (tr[cnt].num=tr[cnt<<1].num+tr[cnt<<1|1].num)%=mod;
    }
    long long qq(int cnt,int l,int r,int L,int R)
    {
        if(l>=L&&r<=R)return tr[cnt].num;
        int mid=(l+r)>>1;
        long long ans=0;
        if(tr[cnt].la)pushdown(cnt,mid-l+1,r-mid);
        if(mid>=L)ans+=qq(cnt<<1,l,mid,L,R);
        if(mid<R)ans+=qq(cnt<<1|1,mid+1,r,L,R);
        return ans%mod;
    }
    void work(int u)
    {
        while(top[1]!=top[u])
        {   
          dd(1,1,n,dfn[top[u]],dfn[u]);
          u=fa[top[u]];
        }
        dd(1,1,n,dfn[1],dfn[u]);
    }
    long long q(int u)
    {
        long long ans=0;
        while(top[1]!=top[u])
        {
            ans+=qq(1,1,n,dfn[top[u]],dfn[u]);
            u=fa[top[u]];
            ans%=mod;
        }
        ans+=qq(1,1,n,dfn[1],dfn[u]);
        return ans;
    }
    int main()
    {
        scanf("%d%d",&n,&qu);
        int x,l,r,z;
        for(int i=1;i<n;++i)
         scanf("%d",&x),add(x+1,i+1);
        dfs(1,1);dfs2(1);
        for(int i=1;i<=qu;++i) 
        {
            scanf("%d%d%d",&l,&r,&z);l++;r++;z++;
            ins[++tot].a=l-1;ins[tot].id=i;ins[tot].tag=-1;ins[tot].wo=z;vec[l-1].push_back(tot);
            ins[++tot].a=r;ins[tot].id=i;ins[tot].tag=1;ins[tot].wo=z;vec[r].push_back(tot);
        }
        for(int i=1;i<=n;++i)
        {work(i);
         for(int j=0;j<vec[i].size();++j)
            {int p=vec[i][j];(ans[ins[p].id]+=ins[p].tag*q(ins[p].wo))%=mod;}
        }
        for(int i=1;i<=qu;++i)
          printf("%d
    ",(ans[i]+mod)%mod);
        return 0;
    }
  • 相关阅读:
    每日总结2021.9.14
    jar包下载mvn
    每日总结EL表达语言 JSTL标签
    每日学习总结之数据中台概述
    Server Tomcat v9.0 Server at localhost failed to start
    Server Tomcat v9.0 Server at localhost failed to start(2)
    链表 java
    MVC 中用JS跳转窗体Window.Location.href
    Oracle 关键字
    MVC 配置路由 反复走控制其中的action (int?)
  • 原文地址:https://www.cnblogs.com/ZH-comld/p/9408044.html
Copyright © 2011-2022 走看看