码迷,mamicode.com
首页 > 其他好文 > 详细

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

时间:2018-10-09 15:35:18      阅读:115      评论:0      收藏:0      [点我收藏+]

标签:getch   enter   ==   线段树   ali   c++   题目   ||   ++   

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

  \(\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\n", (db) Cal(k) / (db) n);
        }
    }
    return 0;
}

 

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

标签:getch   enter   ==   线段树   ali   c++   题目   ||   ++   

原文地址:https://www.cnblogs.com/twilight-sx/p/9760398.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!