题解CF#474(Div.1+Div.2) H-Santa's Gift

Posted twilight-sx

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了题解CF#474(Div.1+Div.2) H-Santa's Gift相关的知识,希望对你有一定的参考价值。

  好久没有写过数据结构题目了,果然还是太不自信。实际上就是要求统计一个式子:

  (sum (c[k]*p[k] - C)^{2})

拆开,分别统计和与平方和

(co[k] * sum p[k]^{2} - 2 * C * co[k] sum p[k] + sum C ^{2})

显然可以用树链剖分 + 线段树维护

平方和在区间 + 1的时候直接用 ((x + 1) ^ {2} = x^2 + 2 * x + 1) 计算即可。

  至于不同的口味的问题,我们给每个口味都开一线段树,动态开点~听起来虽然复杂,但代码实际上超短?????

#include <bits/stdc++.h>
using namespace std;
#define maxn 3000000
#define int long long 
#define db double
int n, m, q, C, cnt, f[maxn], co[maxn], dfn[maxn];
int size[maxn], hson[maxn], top[maxn], fa[maxn];
int root[maxn], mark[maxn * 2], cal[maxn * 2], cal2[maxn * 2], son[maxn * 2][2];

int read()
{
    int x = 0, k = 1;
    char c; c = getchar();
    while(c < 0 || c > 9) { if(c == -) k = -1; c = getchar(); }
    while(c >= 0 && c <= 9) x = x * 10 + c - 0, c = getchar();
    return x * k;
}

struct edge
{
    int cnp, to[maxn], last[maxn], head[maxn];
    edge() { cnp = 2; }
    void add(int u, int v)
    { to[cnp] = v, last[cnp] = head[u], head[u] = cnp ++; }
}E1;

void dfs(int u)
{
    size[u] = 1; int mx = 0, hs = 0;
    for(int i = E1.head[u]; i; i = E1.last[i])
    {
        int v = E1.to[i];
        fa[v] = u; dfs(v); size[u] += size[v];
        if(size[v] >= mx) mx = size[v], hs = v;
    }
    hson[u] = hs;
}

void dfs2(int u, int anc)
{
    dfn[u] = ++ cnt, top[u] = anc;
    if(hson[u]) dfs2(hson[u], anc);
    for(int i = E1.head[u]; i; i = E1.last[i])
        if(E1.to[i] != hson[u]) dfs2(E1.to[i], E1.to[i]);
}

void Add(int &p, int l, int r, int x)
{
    if(!p) p = ++ cnt; mark[p] += x;
    cal2[p] += cal[p] * x + (r - l + 1) * x * x; 
    cal[p] += (r - l + 1) * x * 2;
}

void Push_down(int p, int l, int r)
{
    int mid = (l + r) >> 1;
    if(!mark[p]) return;
    Add(son[p][0], l, mid, mark[p]); Add(son[p][1], mid + 1, r, mark[p]);
    mark[p] = 0;
}

void Push_Up(int p)
{
    int l = son[p][0], r = son[p][1];
    cal2[p] = cal2[l] + cal2[r]; cal[p] = cal[l] + cal[r];
}

void Update(int &p, int l, int r, int L, int R, int x)
{
    if(L > R || l > r) return;
    if(!p) p = ++ cnt;
    if(L <= l && R >= r) { Add(p, l, r, x); return; }
    Push_down(p, l, r); int mid = (l + r) >> 1;
    if(L <= mid) Update(son[p][0], l, mid, L, R, x); 
    if(R > mid) Update(son[p][1], mid + 1, r, L, R, x);
    Push_Up(p);    
}

void T_Update(int k, int u, int x)
{
    for(; u; u = fa[top[u]])
        Update(root[k], 1, n, dfn[top[u]], dfn[u], x);
}

int Cal(int p) 
{ return co[p] * co[p] * cal2[root[p]] - cal[root[p]] * C * co[p] + n * C * C; }

signed main()
{
    n = read(), m = read(), q = read(), C = read();
    for(int i = 1; i <= n; i ++) f[i] = read();
    for(int i = 2; i <= n; i ++) { int x = read(); E1.add(x, i); }
    for(int i = 1; i <= m; i ++) co[i] = read();
    dfs(1), dfs2(1, 1), cnt = m;
    for(int i = 1; i <= m; i ++) root[i] = i;
    for(int i = 1; i <= n; i ++) T_Update(f[i], i, 1);
    for(int i = 1; i <= q; i ++)
    {
        int opt = read();
        if(opt == 1) 
        {
            int x = read(), k = read();
            T_Update(f[x], x, -1), T_Update(f[x] = k, x, 1); 
        }
        else 
        {
            int k = read();
            printf("%lf
", (db) Cal(k) / (db) n);
        }
    }
    return 0;
}

 

以上是关于题解CF#474(Div.1+Div.2) H-Santa's Gift的主要内容,如果未能解决你的问题,请参考以下文章

codeforces比赛题解#868 CF Round #438 (Div.1+Div.2)

Divide by Zero 2018 and Codeforces Round #474 (Div. 1 + Div. 2, combined)G - Bandit Blues

Codeforces Round #618 (Div.1) (Div.2) (CF1299) (CF1300)

补题日记CF#749 Div.1+ Div.2

竞赛题解 - CF Round #524 Div.2

题解 Codeforces Round #616 (Div. 2) (CF1291)