bzoj3683 Falsita

传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=3683

【题解】

首先我们需要化简式子

$ans = P / S$

其中,$S = (sz_x^2 - 1 - \sum_{y = son[x]} sz_y^2) / 2$

这个显然可以预处理。

然后我们经过简单推导可以得出$ P = w_x * (sz_x - 1) + \sum_{y = son[x]} (sz_x - sz_y) * sum_y$

经过如下化简,可以得到

$ P = w_x * sz_x - w_x + \sum_{y = son[x]} (sz_x * sum_y - sz_y * sum_y)$

$ P = w_x * sz_x - w_x + sz_x * (sum_x - w_x) - \sum_{y = son[x]} sz_y * sum_y$

$ P = sz_x * sum_x - w_x - \sum_{y = son[x]} sz_y * sum_y$

然后我们可以树链剖分,每次查询一个点,可以把这个点的信息和重儿子的信息直接查询出来。

然后如果某个轻儿子的整棵子树有一个累加值$\Delta$,那么经过上面推导容易得到整个需要加的系数为$\sum_{y = son[x], y\not= mx[x]} sz_y * sz_y$

系数预处理出来,就可以算答案了。

如果某棵轻儿子的下面某个子树修改了,就从修改的那个点暴力往上跳更新答案,因为这时候不是整棵子树的修改。

暴力更改答案的贡献可以算出来是$sz_y * \Delta$,$y$表示当前的这个点。

每个轻儿子的答案需要在他们的父亲位置进行存储(我们询问是询问父亲的)

然后维护两个树状数组,一个维护每个点加的$\Delta$,一个维护每个子树整体加的$\Delta$,这个是作为轻链计算答案用的。

然后写起来还可以吧?感谢chrt教我这题(逃

# include <stdio.h>
# include <string.h>
# include <iostream>
# include <algorithm>
// # include <bits/stdc++.h>

using namespace std;

typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
const int N = 4e5 + 10, M = 8e5 + 10;
const int mod = 1e9+7;

struct BIT {
    int n; ll c[N];
    # define lb(x) (x & (-x))
    inline void set(int _n) {
        n = _n; memset(c, 0, sizeof c);
    }
    inline void edt(int x, ll d) {
        for (; x<=n; x+=lb(x)) c[x] += d;
    }
    inline ll sum(int x) {
        ll ret = 0;
        for (; x; x-=lb(x)) ret += c[x];
        return ret;
    }
};

struct BIT2 {
    BIT a, b;
    inline void set(int n) {
        a.set(n); b.set(n);
    }
    inline void edt(int x, int y, ll d) {
        a.edt(x, d); a.edt(y+1, -d);
        b.edt(x, d*x); b.edt(y+1, -d*(y+1));
    }
    inline ll sum(int x) {
        return a.sum(x) * (x+1) - b.sum(x);
    }
    inline ll sum(int x, int y) {
        if(x > y) return 0ll;
        return sum(y) - sum(x-1);
    }
}T, C;

int n, w[N], par[N];
int head[N], nxt[N], to[N], tot = 0;
inline void add(int u, int v) {
    ++tot; nxt[tot] = head[u]; head[u] = tot; to[tot] = v;
}

int sz[N], dfn[N], ed[N], DFN, mx[N], top[N];
ll fm[N], fz[N], sum[N], c[N];
inline void dfs(int x) {
    int mxsz = 0, mxid = 0;
    sz[x] = 1; fm[x] = -1; sum[x] = w[x];
    for (int i=head[x]; i; i=nxt[i]) {
        dfs(to[i]);
        if(sz[to[i]] > mxsz) mxsz = sz[to[i]], mxid = to[i];
        sz[x] += sz[to[i]]; sum[x] += sum[to[i]];
        fm[x] -= 1ll * sz[to[i]] * sz[to[i]];
    }
    mx[x] = mxid;
    fm[x] += 1ll * sz[x] * sz[x];
    fm[x] /= 2;
}

inline void dfstop(int x, int tp) {
    dfn[x] = ++DFN; top[x] = tp;
    fz[x] = sum[x] * sz[x] - w[x]; c[x] = 0;
    if(mx[x]) dfstop(mx[x], tp);
    for (int i=head[x]; i; i=nxt[i])
        if(to[i] != mx[x]) {
            dfstop(to[i], to[i]);
            c[x] += 1ll * sz[to[i]] * sz[to[i]];
            fz[x] -= sum[to[i]] * sz[to[i]];
        }
    ed[x] = DFN;
}

inline void jump(int x, ll d) {
    int y;
    while((y = top[x]) != 1) {
        fz[par[y]] -= 1ll * sz[y] * d;
        y = par[y]; x = y;
    }
}

int main() {
    int Q; cin >> n >> Q; T.set(n); C.set(n);
    for (int i=2; i<=n; ++i) scanf("%d", par+i), add(par[i], i);
    for (int i=1; i<=n; ++i) scanf("%d", w+i); 

    dfs(1);
    dfstop(1, 1);

    char op[23]; int x, d;
    while(Q--) {
//        for (int i=1; i<=n; ++i) cout << T.sum(dfn[i], dfn[i]) << endl;
        scanf("%s%d", op, &x);
        if(op[0] == ‘S‘) {
            scanf("%d", &d);
            jump(x, d);
            T.edt(dfn[x], dfn[x], d);
        } else if(op[0] == ‘M‘) {
            scanf("%d", &d);
            jump(x, 1ll * d * sz[x]);
            T.edt(dfn[x], ed[x], d);
            C.edt(dfn[x], ed[x], d);
        } else {
            int y = mx[x];
            ll tem = fz[x] + T.sum(dfn[x], ed[x]) * sz[x] - T.sum(dfn[x], dfn[x]) - (sum[y] + T.sum(dfn[y], ed[y])) * sz[y] - c[x] * C.sum(dfn[x], dfn[x]);
            ld ans = (ld)tem / (ld)fm[x];
            printf("%.6lf\n", (double)ans);
        }
    }
    return 0;
}
/*
4 6

1 2 2

0 -6 3 0

S 2 -5

M 3 8

S 1 -1

M 4 7

M 3 2

Q 2
*/

时间: 2024-11-06 16:16:39

bzoj3683 Falsita的相关文章

POJ3683 Falsita

http://poj.org/problem?id=3683 思路:2-SAT,输出任意一组方案,O(m+n) 1 #include<cstdio> 2 #include<iostream> 3 #include<cmath> 4 #include<cstring> 5 #include<algorithm> 6 int first[2000005],next[2000005],tot,go[2000005]; 7 int First[20000