前言

以此纪念 1:59:14 过的 Div.2 F。

题目翻译

有一棵以 $1$ 为根的有根树,一开始只有节点 $1$。

有 $q(1\leq q\leq 5\times 10^5)$ 个操作:

1 u 表示添加一条 $u\to sz+1$ 的边,其中 $sz$ 为目前树的大小。

2 u w 表示对于以 $u$ 为根的子树,对于所有节点添加 $w(-10^9\leq w\leq 10^9)$ 的权重。

$q$ 次操作后,输出当前树上每个节点的权重。

题目思路

题目不强制在线,我们考虑先离线操作。

离线之后先按操作建出最终状态的树。此时权重都为 $w$。

然后套路性的把这棵树按 Euler Tour 压成一段序列。压好之后同一子树内的节点肯定是连续出现的。

此时 2 操作维护区间加法。操作 1 维护区间清零,因为如果这个点没被建出不会存在以它为根的修改操作,也就是说区间内的数都是一样的,相当于区间加法了。

所以维护区间加法和单点查询操作即可。可以使用 BIT 或 SGT。代码使用的是 BIT。

完整代码

CF submission 230573340

读入量巨大,建议使用快读!

一些东西的用处:

ll cur_tree_sz=1; 当前树大小。

vector<pii> a[2000020]; 建树。

ll in[2000020];ll out[2000020]; Euler Tour 中的左右端点,即最早最晚的出现次数。

ll times; Euler Tour 的时间(长度)。

ll c[4000020]; BIT 数组。change 进行单点修改,query 进行单点查询。区间修改只需要用单点修改差分即可。

赛时着急写得有点拉,上述没提到的部分东西其实没用。

#include <bits/stdc++.h>
using namespace std;
#define getchar() p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 1000000, stdin), p1 == p2) ? EOF : *p1++
char buf[1000000], *p1 = buf, *p2 = buf;
template <typename T>
inline T read()
{
    register T x = 0;
    register int f = 1;
    register char c = getchar();
    for (; c < '0' || c > '9'; c = getchar())
        if (c == '-')
            f = -f;
    for (; c >= '0' && c <= '9'; c = getchar())
        x = (x << 1) + (x << 3) + (c ^ 48);
    return x * f;
}
typedef long long ll;
typedef pair<ll, ll> pii;
int Q;
ll cur_tree_sz = 1;
struct Query
{
    ll op, x, y, t;
} q[2000020];
vector<pii> a[2000020];
ll dep[2000020];
ll in[2000020];
ll out[2000020];
ll id[2000020];
ll times;
// 树按dfs拍成序列
void dfs(int u, int fa, int d)
{
    dep[u] = d;
    in[u] = ++times;
    id[++times] = u;
    for (pii p : a[u])
    {
        ll v = p.first, j = p.second;
        if (v == fa)
            continue;
        dfs(v, u, d + 1);
    }
    out[u] = ++times;
}
ll c[4000020];
const int N = 4000000;
ll lowbit(ll x)
{
    return x & -x;
}
ll query(ll x)
{
    ll ret = 0;
    while (x)
    {
        ret += c[x];
        x -= lowbit(x);
    }
    return ret;
}
void change(ll x, ll y)
{
    while (x <= N)
    {
        c[x] += y;
        x += lowbit(x);
    }
}
void solve()
{
    for (int i = 1; i <= cur_tree_sz + 10; i++)
        dep[i] = id[i] = in[i] = out[i] = 0, a[i].clear();
    for (int i = 1; i <= times + 10; i++)
        c[i] = 0;
    cur_tree_sz = 1;
    times = 0;
    Q = read<int>();
    for (int i = 1; i <= Q; i++)
    {
        q[i].op = read<int>();
        q[i].x = read<int>();
        if (q[i].op & 1)
        {
            a[q[i].x].push_back({++cur_tree_sz, ++times});
        }
        else
        {
            q[i].y = read<ll>();
        }
        q[i].t = i;
    }
    times = 0;
    dfs(1, 0, 1);
    cur_tree_sz = 1;
    for (int i = 1; i <= Q; i++)
    {
        if (q[i].op & 1)
        {
            cur_tree_sz++;
            ll res = query(in[cur_tree_sz]);
            change(in[cur_tree_sz], -res);
            change(out[cur_tree_sz], res);
        }
        else
        {
            change(in[q[i].x], q[i].y);
            change(out[q[i].x], -q[i].y);
        }
    }
    // for (int i = 1; i <= cur_tree_sz; i++)
    //     cout << id[i] << " ";
    // cout << endl;
    for (int i = 1; i <= cur_tree_sz; i++)
        printf("%lld ", query(in[i]));
    printf("\n");
}
int main()
{
    int t;
    cin >> t;
    while (t--)
        solve();
    return 0;
}
最后修改:2023 年 11 月 07 日
v我50吃疯狂星期四