zoukankan      html  css  js  c++  java
  • 【BZOJ】3683: Falsita

    题解

    这道题维护方法比较简单,也有点奇妙

    我们可以很容易求出经过所有点的路径条数,和初始时分子的大小

    然后单点修改的时候,相当于给当前点(v)加上(delta * (siz[v] - 1))

    (v)到根的路径上每个祖先都要加上设(t)(k)在路径上的儿子,(delta * (siz[k] - siz[t]))
    如果想把这种操作快速修改的话,我们把这个操作放到重链上,这样只有重链顶端的父亲需要特殊处理,剩下的值都已经计算好了,用一个标记在线段树上维护就好

    然后考虑区间加,对于修改的这个(v),我们相当于加上(delta * 2 * path[v]),而v所有的儿子以及后代都是一样的操作,所以我们维护第二个标记用来乘上每个节点的(path[u] * 2)

    对于(v)的祖先,就相当于单点修改增加了(siz[v] * delta)

    代码

    #include <bits/stdc++.h>
    #define fi first
    #define se second
    #define pii pair<int,int>
    #define space putchar(' ')
    #define enter putchar('
    ')
    #define mp make_pair
    #define pb push_back
    //#define ivorysi
    #define MAXN 300005
    using namespace std;
    typedef long long int64;
    typedef double db;
    template<class T>
    void read(T &res) {
        res = 0;char c = getchar();T f = 1;
        while(c < '0' || c > '9') {
        	if(c == '-') f = -1;
        	c = getchar();
        }
        while(c >= '0' && c <= '9') {
        	res = res * 10 + c - '0';
        	c = getchar();
        }
        res *= f;
    }
    template<class T>
    void out(T x) {
        if(x < 0) {x = -x;putchar('-');}
        if(x >= 10) {
        	out(x / 10);
        }
        putchar('0' + x % 10);
    }
    struct node {
        int to,next;
    }E[MAXN * 2];
    int N,head[MAXN],sumE,M;
    int siz[MAXN],dfn[MAXN],son[MAXN],idx,top[MAXN],fa[MAXN],dep[MAXN];
    int64 path[MAXN],tag[MAXN],val[MAXN],w[MAXN],sum[MAXN];
    void add(int u,int v) {
        E[++sumE].to = v;
        E[sumE].next = head[u];
        head[u] = sumE;
    }
    struct segment_tree {
        struct node {
            int L,R;
            pair<int64,int64> d;
        }tr[MAXN * 4];
        pair<int64,int64> Merge(pair<int64,int64> a,pair<int64,int64> b) {
            return mp(a.fi + b.fi,a.se + b.se);
        }
        void push_down(int u) {
            tr[u << 1].d = Merge(tr[u].d,tr[u << 1].d);
            tr[u << 1 | 1].d = Merge(tr[u].d,tr[u << 1 | 1].d);
            tr[u].d = mp(0,0);
        }
        void build(int u,int L,int R) {
            tr[u].L = L;tr[u].R = R;
            tr[u].d = mp(0,0);
            if(L == R) return;
            int mid = (L + R) >> 1;
            build(u << 1,L,mid);
            build(u << 1 | 1,mid + 1,R);
        }
        void Add(int u,int l,int r,pair<int64,int64> d) {
            if(tr[u].L == l && tr[u].R == r) {
                tr[u].d = Merge(d,tr[u].d);
                return;
            }
            push_down(u);
            int mid = (tr[u].L + tr[u].R) >> 1;
            if(r <= mid) Add(u << 1,l,r,d);
            else if(l > mid) Add(u << 1 | 1,l,r,d);
            else {Add(u << 1,l,mid,d);Add(u << 1 | 1,mid + 1,r,d);}
        }
        pair<int64,int64> Query(int u,int pos) {
            if(tr[u].L == tr[u].R) return tr[u].d;
            push_down(u);
            int mid = (tr[u].L + tr[u].R) >> 1;
            if(pos <= mid) return Query(u << 1,pos);
            else return Query(u << 1 | 1,pos);
        }
    }Tr;
    
    void Add_Path(int u,int64 v) {
        while(u) {
            int t = top[u];
            if(dfn[t] <= dfn[u] - 1) Tr.Add(1,dfn[t],dfn[u] - 1,mp(v,0));
            if(fa[t]) val[fa[t]] += (siz[fa[t]] - siz[t]) * v;
            u = fa[t];
        }
    }
    
    
    void dfs1(int u) {
        siz[u] = 1;
        dep[u] = dep[fa[u]] + 1;
        sum[u] = w[u];
        dfn[u] = ++idx;
        for(int i = head[u] ; i ; i = E[i].next) {
            int v = E[i].to;
            if(v != fa[u]) {
                fa[v] = u;
                dfs1(v);
                sum[u] += sum[v];
                path[u] += siz[u] * siz[v];
                siz[u] += siz[v];
                if(siz[v] > siz[son[u]]) son[u] = v;
            }
        }
        val[u] += w[u] * (siz[u] - 1);
        for(int i = head[u] ; i ;  i = E[i].next) {
            int v = E[i].to;
            if(v != fa[u]) {
                val[u] += sum[v] * (siz[u] - siz[v]);
            }
        }
        tag[u] = siz[u] - siz[son[u]];
    }
    void dfs2(int u) {
        if(!top[u]) {top[u] = u;}
        if(son[u]) {
            top[son[u]] = top[u];
            dfs2(son[u]);
        }
        for(int i = head[u] ; i ; i = E[i].next) {
            int v = E[i].to;
            if(v != fa[u] && v != son[u]) {
                dfs2(v);
            }
        }
    }
    void Init() {
        read(N);read(M);
        int p;
        for(int i = 2 ; i <= N ; ++i) {
            read(p);
            add(p,i);add(i,p);
        }
        for(int i = 1 ; i <= N ; ++i) read(w[i]);
        dfs1(1);dfs2(1);
        Tr.build(1,1,N);
    }
    
    void Solve() {
        char op[5];
        int u;int64 v;
        while(M--) {
            scanf("%s",op + 1);
            if(op[1] == 'S') {
                read(u);read(v);
                val[u] += (siz[u] - 1) * v;
                Add_Path(u,v);
            }
            else if(op[1] == 'M'){
                read(u);read(v);
                Tr.Add(1,dfn[u],dfn[u] + siz[u] - 1,mp(0,v));
                if(fa[u]) val[fa[u]] += siz[u] * v * (siz[fa[u]] - siz[u]);
                Add_Path(fa[u],siz[u] * v);
            }
            else {
                read(u);
                pair<int64,int64> res = Tr.Query(1,dfn[u]);
                int64 up = res.fi * tag[u] + res.se * 2 * path[u] + val[u];
                int64 down = path[u];
                printf("%.6lf
    ",(db)up / down);
            }
        }
    }
    int main() {
    #ifdef ivorysi
        freopen("f1.in","r",stdin);
    #endif
        Init();
        Solve();
        return 0;
    }
    
  • 相关阅读:
    angular手势事件之on-Hold
    angular 控制器的使用两种模式
    关于IONIC 报错 XX is not a function
    ionic 中$ionicView.beforeEnter 事件的一个bug
    开发一个IONIC应用的首要操作(宏观)
    在线常用库 + API手册
    关于日历实现代码里lunarInfo(农历)数组
    YSlow
    GET and POST
    Yahoo34条军规——雅虎WEB前端网站优化
  • 原文地址:https://www.cnblogs.com/ivorysi/p/9877758.html
Copyright © 2011-2022 走看看