結果

問題 No.2892 Lime and Karin
ユーザー fuppy_kyoprofuppy_kyopro
提出日時 2024-09-16 19:21:04
言語 C++17
(gcc 12.3.0 + boost 1.83.0)
結果
AC  
実行時間 142 ms / 8,000 ms
コード長 11,589 bytes
コンパイル時間 2,878 ms
コンパイル使用メモリ 220,668 KB
実行使用メモリ 36,616 KB
最終ジャッジ日時 2024-09-16 19:21:15
合計ジャッジ時間 10,410 ms
ジャッジサーバーID
(参考情報)
judge3 / judge6
このコードへのチャレンジ
(要ログイン)

テストケース

テストケース表示
入力 結果 実行時間
実行使用メモリ
testcase_00 AC 2 ms
5,248 KB
testcase_01 AC 2 ms
5,376 KB
testcase_02 AC 2 ms
5,376 KB
testcase_03 AC 2 ms
5,376 KB
testcase_04 AC 2 ms
5,376 KB
testcase_05 AC 2 ms
5,376 KB
testcase_06 AC 2 ms
5,376 KB
testcase_07 AC 2 ms
5,376 KB
testcase_08 AC 2 ms
5,376 KB
testcase_09 AC 2 ms
5,376 KB
testcase_10 AC 2 ms
5,376 KB
testcase_11 AC 2 ms
5,376 KB
testcase_12 AC 2 ms
5,376 KB
testcase_13 AC 2 ms
5,376 KB
testcase_14 AC 60 ms
13,184 KB
testcase_15 AC 56 ms
12,544 KB
testcase_16 AC 95 ms
18,304 KB
testcase_17 AC 22 ms
7,296 KB
testcase_18 AC 94 ms
18,304 KB
testcase_19 AC 135 ms
23,296 KB
testcase_20 AC 8 ms
5,376 KB
testcase_21 AC 72 ms
14,848 KB
testcase_22 AC 90 ms
17,664 KB
testcase_23 AC 38 ms
9,728 KB
testcase_24 AC 138 ms
23,680 KB
testcase_25 AC 137 ms
23,532 KB
testcase_26 AC 142 ms
23,552 KB
testcase_27 AC 138 ms
23,680 KB
testcase_28 AC 139 ms
23,680 KB
testcase_29 AC 133 ms
23,552 KB
testcase_30 AC 140 ms
23,552 KB
testcase_31 AC 134 ms
23,680 KB
testcase_32 AC 134 ms
23,552 KB
testcase_33 AC 135 ms
23,680 KB
testcase_34 AC 65 ms
24,848 KB
testcase_35 AC 63 ms
24,848 KB
testcase_36 AC 65 ms
24,828 KB
testcase_37 AC 65 ms
24,788 KB
testcase_38 AC 66 ms
24,852 KB
testcase_39 AC 121 ms
29,128 KB
testcase_40 AC 123 ms
35,892 KB
testcase_41 AC 118 ms
30,360 KB
testcase_42 AC 128 ms
36,616 KB
testcase_43 AC 119 ms
32,324 KB
testcase_44 AC 46 ms
11,264 KB
testcase_45 AC 116 ms
21,376 KB
testcase_46 AC 53 ms
12,416 KB
testcase_47 AC 74 ms
15,488 KB
testcase_48 AC 32 ms
8,704 KB
testcase_49 AC 90 ms
17,280 KB
testcase_50 AC 98 ms
24,336 KB
testcase_51 AC 94 ms
24,200 KB
testcase_52 AC 99 ms
24,304 KB
testcase_53 AC 99 ms
24,320 KB
testcase_54 AC 98 ms
24,320 KB
権限があれば一括ダウンロードができます

ソースコード

diff #

/*
#pragma GCC target("avx2")
#pragma GCC optimize("O3")
#pragma GCC optimize("unroll-loops")
//*/

// #include <atcoder/all>
#include <bits/stdc++.h>

using namespace std;
// using namespace atcoder;

// #define _GLIBCXX_DEBUG

#define DEBUG(x) cerr << #x << ": " << x << endl;
#define DEBUG_VEC(v)                                        \
    cerr << #v << ":";                                      \
    for (int iiiiiiii = 0; iiiiiiii < v.size(); iiiiiiii++) \
        cerr << " " << v[iiiiiiii];                         \
    cerr << endl;
#define DEBUG_MAT(v)                                \
    cerr << #v << endl;                             \
    for (int iv = 0; iv < v.size(); iv++) {         \
        for (int jv = 0; jv < v[iv].size(); jv++) { \
            cerr << v[iv][jv] << " ";               \
        }                                           \
        cerr << endl;                               \
    }
typedef long long ll;
// #define int ll

#define vi vector<int>
#define vl vector<ll>
#define vii vector<vector<int>>
#define vll vector<vector<ll>>
#define pii pair<int, int>
#define pis pair<int, string>
#define psi pair<string, int>
#define pll pair<ll, ll>
template <class S, class T>
pair<S, T> operator+(const pair<S, T> &s, const pair<S, T> &t) {
    return pair<S, T>(s.first + t.first, s.second + t.second);
}
template <class S, class T>
pair<S, T> operator-(const pair<S, T> &s, const pair<S, T> &t) { return pair<S, T>(s.first - t.first, s.second - t.second); }
template <class S, class T>
ostream &operator<<(ostream &os, pair<S, T> p) {
    os << "(" << p.first << ", " << p.second << ")";
    return os;
}
#define rep(i, n) for (int i = 0; i < (int)(n); i++)
#define rep1(i, n) for (int i = 1; i <= (int)(n); i++)
#define rrep(i, n) for (int i = (int)(n) - 1; i >= 0; i--)
#define rrep1(i, n) for (int i = (int)(n); i > 0; i--)
#define REP(i, a, b) for (int i = a; i < b; i++)
#define in(x, a, b) (a <= x && x < b)
#define all(c) c.begin(), c.end()
void YES(bool t = true) {
    cout << (t ? "YES" : "NO") << endl;
}
void Yes(bool t = true) { cout << (t ? "Yes" : "No") << endl; }
void yes(bool t = true) { cout << (t ? "yes" : "no") << endl; }
void NO(bool t = true) { cout << (t ? "NO" : "YES") << endl; }
void No(bool t = true) { cout << (t ? "No" : "Yes") << endl; }
void no(bool t = true) { cout << (t ? "no" : "yes") << endl; }
template <class T>
bool chmax(T &a, const T &b) {
    if (a < b) {
        a = b;
        return 1;
    }
    return 0;
}
template <class T>
bool chmin(T &a, const T &b) {
    if (a > b) {
        a = b;
        return 1;
    }
    return 0;
}
template <class T, class U>
T ceil_div(T a, U b) {
    return (a + b - 1) / b;
}
template <class T>
T safe_mul(T a, T b) {
    if (a == 0 || b == 0) return 0;
    if (numeric_limits<T>::max() / a < b) return numeric_limits<T>::max();
    return a * b;
}
#define UNIQUE(v) v.erase(std::unique(v.begin(), v.end()), v.end());
const ll inf = 1000000001;
const ll INF = (ll)1e18 + 1;
const long double pi = 3.1415926535897932384626433832795028841971L;
int popcount(ll t) { return __builtin_popcountll(t); }
vector<int> gen_perm(int n) {
    vector<int> ret(n);
    iota(all(ret), 0);
    return ret;
}
// int dx[4] = {1, 0, -1, 0}, dy[4] = {0, 1, 0, -1};
// int dx2[8] = { 1,1,0,-1,-1,-1,0,1 }, dy2[8] = { 0,1,1,1,0,-1,-1,-1 };
vi dx = {0, 0, -1, 1}, dy = {-1, 1, 0, 0};
vi dx2 = {1, 1, 0, -1, -1, -1, 0, 1}, dy2 = {0, 1, 1, 1, 0, -1, -1, -1};
struct Setup_io {
    Setup_io() {
        ios_base::sync_with_stdio(0), cin.tie(0), cout.tie(0);
        cout << fixed << setprecision(25);
        cerr << fixed << setprecision(25);
    }
} setup_io;
// constexpr ll MOD = 1000000007;
constexpr ll MOD = 998244353;
// #define mp make_pair

struct DSUOnTree {
    // https://nyaannyaan.github.io/library/tree/dsu-on-tree.hpp.html
    // https://codeforces.com/blog/entry/44351

    vector<vector<int>> G;
    int n;
    // 頂点 u の部分木は ord の [from[u], to[u]) の範囲に入っている
    vector<int> sub, ord, from, to;
    int root;

    int dfs_sub(int now, int par) {
        sub[now] = 1;

        if (G[now].size() >= 2 && G[now][0] == par) {
            // 最初の子は Big Child になるようにする
            swap(G[now][0], G[now][1]);
        }

        for (int i = 0; i < G[now].size(); i++) {
            int to = G[now][i];
            if (to == par) continue;
            sub[now] += dfs_sub(to, now);

            if (i != 0 && sub[G[now][0]] < sub[to]) {
                swap(G[now][0], G[now][i]);
            }
        }

        return sub[now];
    }

    void dfs_ord(int now, int par, int &idx) {
        from[now] = idx;
        ord[idx++] = now;

        for (int to : G[now]) {
            if (to == par) continue;
            dfs_ord(to, now, idx);
        }
        to[now] = idx;
    }

  public:
    DSUOnTree(vector<vector<int>> G, int root) : G(G), n(G.size()), root(root) {
        sub.resize(n);
        from.resize(n);
        to.resize(n);
        ord.reserve(n);

        dfs_sub(root, -1);
        int idx = 0;
        dfs_ord(root, -1, idx);
    }

    using F = function<void(int)>;
    void run(F update, F query, F clear) {
        // 各関数を通じて、外部に用意した配列やセグ木にアクセスする想定
        // update(u): 頂点 u 単体に関して値を更新する
        // query(u): 頂点 u が属する部分木に関しての更新が終わった状態でクエリを処理する
        // clear(u): 頂点 u 単体に関しての更新を解除する
        // verify: https://judge.yosupo.jp/submission/235963

        auto dfs = [&](auto &&self, int now, int par, bool keep) -> void {
            // dfs Small Child
            for (int i = 1; i < G[now].size(); i++) {
                if (G[now][i] == par) continue;
                self(self, G[now][i], now, false);
            }

            // dfs Big Child
            if (sub[now] > 1) {
                self(self, G[now][0], now, true);
            }

            // update Small Child
            if (sub[now] > 1) {
                int bc = G[now][0];
                for (int i = to[bc]; i < to[now]; i++) {
                    update(ord[i]);
                }
            }

            update(now);
            query(now);

            if (!keep) {
                for (int i = from[now]; i < to[now]; i++) {
                    clear(ord[i]);
                }
            }
            return;
        };

        dfs(dfs, root, -1, true);
    }

    using F2 = function<void(int, int)>;
    void run_every_pair(F update, F query_root, F2 query_light, F clear) {
        // 各関数を通じて、外部に用意した配列やセグ木にアクセスする想定。
        // 全ての異なる頂点ペアに関するクエリを処理する。同じ頂点ペアに関するクエリがある場合は別途処理する必要がある。
        // update(u): 頂点 u 単体に関して値を更新する
        // query_root(u): 頂点 u を根として追加する時に、u とその子孫に関するクエリを処理する。
        // query_light(r, u): 頂点 r が根の時に頂点 u を Small Child として追加する時に、
        //      u と「r の Big Child, および r の処理済みの Small Child」に関するクエリを処理する。
        //      u と r に関するクエリは query_root で処理されるので、ここでは扱わない
        // clear(u): 頂点 u 単体に関しての更新を解除する

        auto dfs = [&](auto &&self, int now, int par, bool keep) -> void {
            // dfs Small Child
            for (int i = 1; i < G[now].size(); i++) {
                if (G[now][i] == par) continue;
                self(self, G[now][i], now, false);
            }

            // dfs Big Child
            if (sub[now] > 1) {
                self(self, G[now][0], now, true);
            }

            // update Small Child
            if (sub[now] > 1) {
                for (int i = 1; i < G[now].size(); i++) {
                    if (G[now][i] == par) continue;

                    int ch = G[now][i];
                    // Big Child とすでに処理済みの Small Child に関するクエリを処理
                    for (int u = from[ch]; u < to[ch]; u++) {
                        query_light(now, ord[u]);
                    }
                    for (int u = from[ch]; u < to[ch]; u++) {
                        update(ord[u]);
                    }
                }
            }

            // 根と子孫の間のクエリを処理
            query_root(now);
            update(now);

            if (!keep) {
                for (int i = from[now]; i < to[now]; i++) {
                    clear(ord[i]);
                }
            }
            return;
        };

        dfs(dfs, root, -1, true);
    }
};

class Bit {
  public:
    int n;
    vl bit; // 0-index

    Bit(int _n) {
        n = _n;
        bit.resize(n);
    }

    // [0, i)
    ll sum(int i) {
        ll s = 0;
        while (i > 0) {
            s += bit[i - 1];
            i -= i & -i;
        }
        return s;
    }

    // [l, r)
    ll sum(int l, int r) {
        if (l >= r) return 0;
        return sum(r) - sum(l);
    }

    void add(int i, ll x) {
        i++;
        while (i <= n) {
            bit[i - 1] += x;
            i += i & -i;
        }
    }

    ll min_xth(int x) {
        // なぜか 1-indexed
        // x = 0 の時は必ず 0 が返っていそう
        int left = -1, right = n;
        while (left + 1 < right) {
            int mid = (left + right) / 2;
            int temp = sum(mid + 1);
            if (temp < x) {
                left = mid;
            } else {
                right = mid;
            }
        }
        return right;
    }

    ll bubble(vi p) {
        int n = p.size();
        ll ans = 0;
        for (int j = 0; j < n; j++) {
            ans += (j - sum(p[j] + 1));
            add(p[j], 1);
        }
        return ans;
    }
};

signed main() {
    int n;
    cin >> n;

    vii G(n);
    rep(i, n - 1) {
        int u, v;
        cin >> u >> v;
        u--;
        v--;
        G[u].push_back(v);
        G[v].push_back(u);
    }

    string s;
    cin >> s;
    vi a(n);
    rep(i, n) {
        if (s[i] == '1')
            a[i] = 1;
        else
            a[i] = -1;
    }

    vi rui(n);
    auto dfs_rui = [&](auto &&f, int now, int par, int d) -> void {
        rui[now] = d + a[now];
        for (int to : G[now]) {
            if (to == par) continue;
            f(f, to, now, rui[now]);
        }
    };
    dfs_rui(dfs_rui, 0, -1, 0);

    int OFF = n;
    Bit bit(2 * n + 1);

    ll ans = 0;
    auto update = [&](int u) {
        bit.add(rui[u] + OFF, 1);
    };
    auto query_root = [&](int u) {
        // DEBUG(u);
        // for (int i = -n; i <= n; i++) {
        //     DEBUG(pii(i, bit.sum(i + OFF, i + 1 + OFF)));
        // }

        int p = rui[u] - a[u];
        // x - p > 0
        // x > p
        ans += bit.sum(p + 1 + OFF, 2 * n + 1);
    };
    auto query_light = [&](int r, int u) {
        int p = rui[r] - a[r];
        int val1 = rui[u] - p;
        // val1 + x - p - a[r] > 0
        // x > p + a[r] - val1
        ans += bit.sum(p + a[r] - val1 + 1 + OFF, 2 * n + 1);
    };
    auto clear = [&](int u) {
        bit.add(rui[u] + OFF, -1);
    };

    DSUOnTree dsu(G, 0);
    dsu.run_every_pair(update, query_root, query_light, clear);

    rep(i, n) {
        if (a[i] == 1) ans++;
    }

    cout << ans << endl;
}
0