QOJ.ac
QOJ
ID | Problem | Submitter | Result | Time | Memory | Language | File size | Submit time | Judge time |
---|---|---|---|---|---|---|---|---|---|
#462538 | #3226. Distance Sum | propane | WA | 0ms | 3544kb | C++20 | 10.3kb | 2024-07-03 20:39:25 | 2024-07-03 20:39:26 |
Judging History
answer
#include<iostream>
#include<cstring>
#include<vector>
#include<numeric>
#include<functional>
#include<algorithm>
using namespace std;
using LL = long long;
// d(u, v) = dep(u) + dep(v) - 2 dep(anc)
// 维护一个点的子树内已经有的深度和 减去两倍的本身深度 以及点的个数
// 因为会重复,所以需要类似点分树维护子树的贡献,减去避免重复计数
struct Info{
LL dep = 0, len = 0, cnt = 0, sum = 0;
};
struct Tag{
LL cnt = 0, sum = 0;
};
Info operator+(const Info &a, const Info &b){
return {a.dep + b.dep, a.len + b.len, a.cnt + b.cnt, a.sum + b.sum};
}
void apply(Info &x, Tag &a, Tag f){
x.cnt += x.len * f.cnt;
x.sum -= 2 * x.dep * f.cnt;
x.sum += x.len * f.sum;
a.cnt += f.cnt;
a.sum += f.sum;
}
template<class Info, class Tag>
struct LazySegmentTree{
int n;
vector<Info> info;
vector<Tag> tag;
LazySegmentTree() {}
LazySegmentTree(int n, Info _init = Info()){
init(vector<Info>(n, _init));
}
LazySegmentTree(const vector<Info> &_init){
init(_init);
}
void init(const vector<Info> &_init){
n = (int)_init.size();
info.assign((n << 2) + 1, Info());
tag.assign((n << 2) + 1, Tag());
function<void(int, int, int)> build = [&](int p, int l, int r){
if (l == r){
info[p] = _init[l - 1];
return;
}
int m = (l + r) / 2;
build(2 * p, l, m);
build(2 * p + 1, m + 1, r);
pull(p);
};
build(1, 1, n);
}
void pull(int p){
info[p] = info[2 * p] + info[2 * p + 1];
}
void apply(int p, const Tag &v){
::apply(info[p], tag[p], v);
}
void push(int p){
apply(2 * p, tag[p]);
apply(2 * p + 1, tag[p]);
tag[p] = Tag();
}
void modify(int p, int l, int r, int x, const Info &v){
if (l == r){
info[p] = v;
return;
}
int m = (l + r) / 2;
push(p);
if (x <= m){
modify(2 * p, l, m, x, v);
}
else{
modify(2 * p + 1, m + 1, r, x, v);
}
pull(p);
}
void modify(int p, const Info &v){
modify(1, 1, n, p, v);
}
Info query(int p, int l, int r, int x, int y){
if (l > y || r < x){
return Info();
}
if (l >= x && r <= y){
return info[p];
}
int m = (l + r) / 2;
push(p);
return query(2 * p, l, m, x, y) + query(2 * p + 1, m + 1, r, x, y);
}
Info query(int l, int r){
return query(1, 1, n, l, r);
}
void modify(int p, int l, int r, int x, int y, const Tag &v){
if (l > y || r < x){
return;
}
if (l >= x && r <= y){
apply(p, v);
return;
}
int m = (l + r) / 2;
push(p);
modify(2 * p, l, m, x, y, v);
modify(2 * p + 1, m + 1, r, x, y, v);
pull(p);
}
void modify(int l, int r, const Tag &v){
return modify(1, 1, n, l, r, v);
}
};
// 1_based HLD
struct Edge{
int to;
int w;
operator int() const { return to; }
};
struct HLD{
int n;
vector<int> sz, top, dep, fa, in, out, seq;
vector<LL> dis;
vector<vector<Edge> > g;
int ts;
HLD(const vector<vector<Edge> > &g, int root = 1) : n(int(g.size()) - 1), g(g) {
ts = 0;
sz.resize(n + 1);
top.resize(n + 1);
dep.resize(n + 1);
fa.resize(n + 1);
in.resize(n + 1);
out.resize(n + 1);
seq.resize(n + 1);
dis.resize(n + 1);
dep[root] = 1;
top[root] = root;
dfs_sz(root);
dfs_hld(root);
}
void dfs_sz(int u){
if (fa[u]){
for(auto it = g[u].begin(); it != g[u].end(); it++){
if (*it == fa[u]){
g[u].erase(it);
break;
}
}
}
sz[u] = 1;
for(auto &j : g[u]){
fa[j] = u;
dep[j] = dep[u] + 1;
dis[j] = dis[u] + j.w;
dfs_sz(j);
sz[u] += sz[j];
if (sz[j] > sz[g[u][0]])
swap(j, g[u][0]);
}
}
void dfs_hld(int u){
in[u] = ++ts;
seq[in[u]] = u;
for (auto j : g[u]){
top[j] = (j == g[u][0] ? top[u] : j);
dfs_hld(j);
}
out[u] = ts;
}
int lca(int u, int v){
while (top[u] != top[v]){
if (dep[top[u]] > dep[top[v]]){
u = fa[top[u]];
}
else{
v = fa[top[v]];
}
}
return dep[u] < dep[v] ? u : v;
}
int dist(int u, int v){
return dep[u] + dep[v] - 2 * dep[lca(u, v)];
}
bool in_subtree(int u, int v){
return in[v] <= in[u] && in[u] <= out[v];
}
int jump(int u, int k) {
if (dep[u] < k){
return -1;
}
int d = dep[u] - k;
while (dep[top[u]] > d){
u = fa[top[u]];
}
return seq[in[u] - dep[u] + d];
}
int rooted_lca(int a, int b, int c){
return lca(a, b) ^ lca(b, c) ^ lca(c, a);
}
template<typename Q>
void modify_path(int u, int v, const Q &q, bool edge = false){
while(top[u] != top[v]){
if (dep[top[u]] < dep[top[v]]) swap(u, v);
q(in[top[u]], in[u]);
u = fa[top[u]];
}
if (dep[u] > dep[v]) swap(u, v);
q(in[u] + edge, in[v]);
}
template<typename Q>
void modify_subtree(int u, const Q &q){
q(in[u], out[u]);
}
template<typename T, typename Q>
T query_path(int u, int v, const Q &q, bool edge = false){
T ret = T();
while(top[u] != top[v]){
if (dep[top[u]] < dep[top[v]]) swap(u, v);
ret = q(in[top[u]], in[u]) + ret;
u = fa[top[u]];
}
if (dep[u] > dep[v]) swap(u, v);
return q(in[u] + edge, in[v]) + ret;
}
template<typename T, typename Q>
T query_subtree(int u, const Q &q){
return q(in[u], out[u]);
}
template<typename T, typename Q, typename F>
T query_path_noncommutative(int u, int v, const Q &q, const F &f, bool edge = false){
T left = T(), right = T();
while(top[u] != top[v]){
if (dep[top[u]] < dep[top[v]]) swap(u, v), swap(left, right);
left = q(in[top[u]], in[u]) + left;
u = fa[top[u]];
}
if (dep[u] > dep[v]) swap(u, v), swap(left, right);
return f(left, q(in[u] + edge, in[v]) + right);
}
pair<vector<int>, vector<pair<int, int> > > compress(vector<int> v){
auto cmp = [&](int a, int b) { return in[a] < in[b]; };
sort(v.begin(), v.end(), cmp);
v.erase(unique(v.begin(), v.end()), v.end());
const int k = (int)v.size();
for(int i = 0; i + 1 < k; i++){
v.push_back(lca(v[i], v[i + 1]));
}
sort(v.begin(), v.end(), cmp);
v.erase(unique(v.begin(), v.end()), v.end());
vector<pair<int, int> > edges;
vector<int> stk;
for(auto x : v){
while(!stk.empty() && out[stk.back()] < in[x]){
stk.pop_back();
}
if (!stk.empty()){
edges.push_back({stk.back(), x});
}
stk.push_back(x);
}
return {v, edges};
}
};
int main(){
#ifdef LOCAL
freopen("data.in", "r", stdin);
freopen("data.out", "w", stdout);
#endif
cin.tie(0);
cout.tie(0);
ios::sync_with_stdio(0);
int n;
cin >> n;
vector<vector<Edge> > g(n + 1);
for(int i = 2; i <= n; i++){
int p, w;
cin >> p >> w;
g[p].push_back({i, w});
}
HLD hld(g);
vector<Info> init1(n), init2(n);
for(int i = 1; i <= n; i++){
int x = hld.seq[i];
init1[i - 1] = {hld.dis[x], 1, 0, 0};
}
for(int i = 2; i <= n; i++){
int x = hld.fa[hld.seq[i]];
init2[i - 1] = {hld.dis[x], 1, 0, 0};
}
LazySegmentTree<Info, Tag> seg1(init1), seg2(init2);
auto change = [&](int x){
{
auto f = [&](int l, int r){
seg1.modify(l, r, {1, hld.dis[x]});
};
hld.modify_path(1, x, f);
}
if (x != 1){
auto f = [&](int l, int r){
seg2.modify(l, r, {1, hld.dis[x]});
};
int t = hld.jump(x, hld.dep[x] - hld.dep[1] - 1);
hld.modify_path(t, x, f);
}
};
auto get = [&](int x){
Info res1 = Info(), res2 = Info();
{
auto q = [&](int l, int r){
return seg1.query(l, r);
};
res1 = hld.query_path<Info>(1, x, q);
}
{
auto q = [&](int l, int r){
return seg2.query(l, r);
};
res2 = hld.query_path<Info>(1, x, q);
}
LL cnt = res1.cnt - res2.cnt;
LL sum = res1.sum - res2.sum;
return sum + cnt * hld.dis[x];
};
cout << 0 << '\n';
int last = 1;
change(1);
for(int i = 2; i <= n; i++){
change(i);
int anc = hld.lca(last, i);
int len = hld.dep[i] + hld.dep[last] - 2 * hld.dep[anc];
auto get_pos = [&](int t){
int x = -1;
if (t <= hld.dep[last] - hld.dep[anc]){
x = hld.jump(last, t);
}
else{
x = hld.jump(i, len - t);
}
return x;
};
auto f = [&](int t){
return get(get_pos(t));
};
int l = 0, r = len;
while(l < r){
int m1 = l + (r - l) / 3;
int m2 = r - (r - l) / 3;
if (f(m1) >= f(m2)) l = m1 + 1;
else r = m2 - 1;
}
last = get_pos(r);
cout << f(r) << '\n';
}
}
Details
Tip: Click on the bar to expand more detailed information
Test #1:
score: 0
Wrong Answer
time: 0ms
memory: 3544kb
input:
10 5 1 2 1 1 1 4 1 2 1 5 1 2 1 2 1 5 1
output:
0 3 4 6 7 8 9 11 12 14
result:
wrong answer 5th lines differ - expected: '6', found: '7'