zoukankan      html  css  js  c++  java
  • 宝藏探寻

    宝藏探寻 树上倍增

    小μ发现了一个矿洞,里面出产珍贵的紫萤石。紫萤石的价值与它的质量成正比。可以认为,一个质量为x的紫萤石的价值为x2。经过探查,发现这个矿洞里面有一块巨大的紫萤石,它的结构是一个N个点,N-1条边的无向无环联通图。其中每一个节点i可以看成是一个质量为a[i]的紫萤石。有N-1条紫萤石边,每条边连接两个紫萤石节点,紫萤石边的质量可以忽略不计。显然这个巨大的紫萤石的价值为(Σa[i])2,然而直接带走这个巨大的紫萤石是不现实的,因此,需要选择一条路径(x,y),其中x和y是路径的两个端点,x≠y。现在要将x到y上的所有的紫萤石节点都炸碎。一个紫萤石节点被炸碎后,和它相连的边也会消失。现在有M次询问,每次给出路径的两个端点x,y(x≠y),你需要给出炸碎这条路径后,剩余的若干个紫萤石块的价值之和。每次询问是独立的。你可以认为,每次询问后整个紫萤石结构恢复原状。输入:第一行两个数:N<=200000,M<=100000第二行N个数:a[i]<=1000接下来M行,每行两个数x,y,表示一条以x和y为端点的路径。(x≠y)

    ​ 这道题考试的时候没想到倍增,然后只有五十分。。其实就是一个需要特殊处理的倍增而已。

    #include <cstdio>
    using namespace std;
    
    typedef long long LL;
    const LL maxn=2e5+5, logn=20;
    inline void swap(LL &x, LL &y){
        LL tmp=x; x=y; y=tmp; }
    inline LL sqr(LL x){ return x*x; }
    
    class Graph{
    public:
        struct Edge{
            LL to, next; Graph *belong;
            void set(LL x, LL y, Graph *g){
                to=x; next=y; belong=g; }
            inline LL operator*(){ return to; }
            Edge& operator++(){
                return *this=belong->edge[next]; }
        };
        void addedge(LL x, LL y){
            edge[++cntedge].set(y, fir[x], this);
            fir[x]=cntedge;
        }
        Edge& getlink(LL x){ return edge[fir[x]]; }
    private:
        LL cntedge, fir[maxn];
        Edge edge[maxn*2];
    };
    
    Graph g;
    LL n, m, a[maxn], cnta[maxn], dep[maxn], fa[maxn];
    LL p[maxn][logn], f[maxn][logn];
    
    void predfs(LL now, LL pre){
        Graph::Edge e;
        p[now][0]=now; fa[now]=pre;
        for (LL i=1; i<logn; ++i)
            p[now][i]=p[fa[p[now][i-1]]][i-1];
        cnta[now]+=a[now];
        for (e=g.getlink(now); *e; ++e){
            if (*e==pre) continue;
            dep[*e]=dep[now]+1;
            predfs(*e, now);
            cnta[now]+=cnta[*e];
        }
    }
    
    void dfs(LL now, LL pre){ //倍增
        Graph::Edge e;
        for (e=g.getlink(now); *e; ++e)
            if (*e!=pre) f[now][0]+=sqr(cnta[*e]);
        for (LL i=1; i<logn; ++i)
            f[now][i]=f[now][i-1]+f[fa[p[now][i-1]]][i-1]
                    -sqr(cnta[p[now][i-1]]);
        for (e=g.getlink(now); *e; ++e)
             if (*e!=pre) dfs(*e, now);
    }
    
    LL solve(LL x, LL y){
        if (dep[x]>dep[y]) swap(x, y);
        LL ans=0, minusx=0, minusy=0;
        for (LL i=logn-1; i>=0; --i)
            if (dep[x]<dep[p[y][i]]){
                ans+=f[y][i]-minusy;
                minusy=sqr(cnta[p[y][i]]);
                y=fa[p[y][i]];
            }
        for (LL i=logn-1; i>=0; --i)
            if (p[x][i]!=p[y][i]){
                ans+=f[x][i]+f[y][i]-minusx-minusy;
                minusx=sqr(cnta[p[x][i]]);
                minusy=sqr(cnta[p[y][i]]);
                x=fa[p[x][i]]; y=fa[p[y][i]];
            }
        LL lca=x; ans+=f[lca][0]-minusx-minusy;
        ans+=sqr(cnta[1]-cnta[lca]);
        return ans;
    }
    
    int main(){
        scanf("%lld%lld", &n, &m);
        for (LL i=1; i<=n; ++i) scanf("%lld", &a[i]);
        LL x, y;
        for (LL i=1; i<n; ++i){
            scanf("%lld%lld", &x, &y);
            g.addedge(x, y); g.addedge(y, x);
        }
        predfs(1, 0);
        dfs(1, 0);
        for (LL i=0; i<m; ++i){
            scanf("%lld%lld", &x, &y);
            printf("%lld
    ", solve(x, y));
        }
        return 0;
    }
    
  • 相关阅读:
    python基础(5)
    python基础(4)
    python基础(3)
    python基础(2)
    第一个python程序(2)
    第一个python教程(1)
    【jQuery】
    【JavaScript】
    【练习】HTML+CSS
    【练习】Html
  • 原文地址:https://www.cnblogs.com/MyNameIsPc/p/7715602.html
Copyright © 2011-2022 走看看