zoukankan      html  css  js  c++  java
  • BZOJ4381[POI2015]Odwiedziny——分块+长链剖分

    题目描述

    给定一棵n个点的树,树上每条边的长度都为1,第i个点的权值为a[i]。
    Byteasar想要走遍这整棵树,他会按照某个1到n的全排列b走n-1次,第i次他会从b[i]点走到b[i+1]点,并且这一次的步伐大小为c[i]。
    对于一次行走,假设起点为x,终点为y,步伐为k,那么Byteasar会从x开始,每步往前走k步,如果最后不足k步就能到达y,那么他会一步走到y。
    请帮助Byteasar统计出每一次行走时经过的所有点的权值和。

    输入

    第一行包含一个正整数n(2<=n<=50000)。表示节点的个数。
    第二行包含n个正整数,其中第i个数为a[i](1<=a[i]<=10000),分别表示每个点的权值。
    接下来n-1行,每行包含两个正整数u,v(1<=u,v<=n),表示u与v之间有一条边。
    接下来一行包含n个互不相同的正整数,其中第i个数为b[i](1<=b[i]<=n),表示行走路线。
    接下来一行包含n-1个正整数,其中第i个数为c[i](1<=c[i]<n),表示每次行走的步伐大小。

    输出

    包含n-1行,每行一个正整数,依次输出每次行走时经过的所有点的权值和

    样例输入

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

    样例输出

    10
    6
    10
    5
        
      因为k的大小不确定,所以分情况来做。设p=sqrt(n),当k<=p时,可以预处理出f[i][j]表示i节点以j步伐一直往上走,直到走到根节点(i节点的深度如果不是k的倍数,根节点不计入)为止能得到的点权和,查询时直接求就好了.当k>p时,就要暴力往上走了,可以用重链剖分来实现,单次查询时间复杂度是O(logn+√n),但有一种时间复杂度更优的做法——长链剖分,因为长链剖分可以O(1)查询一个点的k级祖先,因此最多爬√n次,单次查询时间复杂度O(√n)。如何实现参见->长链剖分
    #include<set>
    #include<map>
    #include<stack>
    #include<queue>
    #include<cmath>
    #include<vector>
    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    #define ll long long
    using namespace std;
    int n;
    int x,y;
    int tot;
    int mask;
    int b[50010];
    int a[50010];
    int k[50010];
    int d[50010];
    int st[50010];
    int mx[50010];
    int to[100010];
    int son[50010];
    int top[50010];
    int head[50010];
    int next[100010];
    int f[50010][17];
    int up[50010][300];
    vector<int>s[50010];
    vector<int>t[50010];
    void add(int x,int y)
    {
        tot++;
        next[tot]=head[x];
        head[x]=tot;
        to[tot]=y;
    }
    void dfs(int x)
    {
        d[x]=d[f[x][0]]+1;
        mx[x]=d[x];
        for(int i=1;i<=16;i++)
        {
            if(f[x][i-1])
            {
                f[x][i]=f[f[x][i-1]][i-1];
            }
            else
            {
                break;
            }
        }
        int fx=x;
        for(int i=1;i<=mask;i++)
        {
            fx=f[fx][0];
            up[x][i]=a[x]+up[fx][i];
        }
        for(int i=head[x];i;i=next[i])
        {
            if(to[i]!=f[x][0])
            {
                f[to[i]][0]=x;
                dfs(to[i]);
                mx[x]=max(mx[x],mx[to[i]]);
                if(mx[to[i]]>mx[son[x]])
                {
                    son[x]=to[i];
                }
            }
        }
    }
    void dfs2(int x,int tp)
    {
        top[x]=tp;
        if(son[x])
        {
            dfs2(son[x],tp);
        }
        for(int i=head[x];i;i=next[i])
        {
            if(to[i]!=f[x][0]&&to[i]!=son[x])
            {
                dfs2(to[i],to[i]);
            }
        }
    }
    void find(int x)
    {
        int rt=x;
        int len=mx[x]-d[x];
        x=f[rt][0];
        while(d[rt]-d[x]<=len&&x)
        {
            s[rt].push_back(x);
            x=f[x][0];
        }
        x=rt;
        while(son[x])
        {
            t[rt].push_back(son[x]);
            x=son[x];
        }
    }
    int find_ancestor(int x,int k)
    {
        if(k==0)
        {
            return x;
        }
        if(d[x]<=k)
        {
            return 0;
        }
        x=f[x][st[k]];
        k-=(1<<st[k]);
        if(k==0)
        {
            return x;
        }
        if(k==d[x]-d[top[x]])
        {
            return top[x];
        }
        if(k<d[x]-d[top[x]])
        {
            return t[top[x]][d[x]-d[top[x]]-k-1];
        }
        return s[top[x]][k-d[x]+d[top[x]]-1];
    }
    int lca(int x,int y)
    {
        if(d[x]<d[y])
        {
            swap(x,y);
        }
        int dep=d[x]-d[y];
        for(int i=0;i<=16;i++)
        {
            if((dep&(1<<i))!=0)
            {
                x=f[x][i];
            }
        }
        if(x==y)
        {
            return x;
        }
        for(int i=16;i>=0;i--)
        {
            if(f[x][i]!=f[y][i])
            {
                x=f[x][i];
                y=f[y][i];
            }
        }
        return f[x][0];
    }
    int query(int x,int y,int step)
    {
        int res=0;
        int anc=lca(x,y);
        int lx=d[x]-d[anc];
        int ly=d[y]-d[anc];
        if(step>mask)
        {
            res+=a[x]+a[y];
            while(lx>step)
            {
                x=find_ancestor(x,step);
                res+=a[x];
                lx-=step;
            }
            if(lx+ly-1>=step)
            {
                y=find_ancestor(y,lx+ly-(lx+ly-1)/step*step);
                res+=a[y];
                ly=(lx+ly-1)/step*step-lx;
                while(ly>step)
                {
                    y=find_ancestor(y,step);
                    res+=a[y];
                    ly-=step;
                }
            }
            if(x!=anc&&y!=anc&&(lx==step||ly==step)) 
            {
                res+=a[anc];
            }
        }
        else
        {
            if(lx+ly<=step)
            {
                res=a[x]+a[y];
            }
            else
            {
                res+=a[y];
                y=find_ancestor(y,lx+ly-(lx+ly-1)/step*step);
                ly=(lx+ly-1)/step*step-lx;
                res+=up[x][step]-up[find_ancestor(x,(lx/step)*step+step)][step];
                if(ly>=0)
                {
                    res+=up[y][step]-up[find_ancestor(y,(ly/step)*step+step)][step];
                }
                if(lx%step==0)
                {
                    res-=a[anc];
                }
            }
        }
        return res;
    }
    int main()
    {
        scanf("%d",&n);
        mask=sqrt(n);
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&a[i]);
        }
        for(int i=1;i<n;i++)
        {
            scanf("%d%d",&x,&y);
            add(x,y);
            add(y,x);
        }
        dfs(1);
        dfs2(1,1);
        for(int i=1;i<=n;i++)
        {
            if(i==top[i])
            {
                find(i);
            }
        }
        st[1]=0;
        for(int i=2;i<=n;i++)
        {
            st[i]=st[i>>1]+1;
        }
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&b[i]);
        }
        for(int i=1;i<n;i++)
        {
            scanf("%d",&k[i]);
        }
        for(int i=1;i<n;i++)
        {
            printf("%d
    ",query(b[i],b[i+1],k[i]));
        }
    }
  • 相关阅读:
    课程一(Neural Networks and Deep Learning),第一周(Introduction to Deep Learning)—— 1、经常提及的问题
    递归、字节流、文件复制_DAY20
    IO概述、异常、File文件类_DAY19
    某书2018笔试题之薯券
    某书2018笔试题之翻转数字
    某书2018笔试题之字符串中最大子数字串
    批量发货的启示
    为什么易燥易怒以及柔润相处的练习
    编程漫谈(十五):编程与软件开发
    使用函数式编程消除重复无聊的foreach代码(Scala示例)
  • 原文地址:https://www.cnblogs.com/Khada-Jhin/p/9581321.html
Copyright © 2011-2022 走看看