結果
問題 | No.399 動的な領主 |
ユーザー | Kenshin-Y |
提出日時 | 2023-04-01 13:28:27 |
言語 | C++17 (gcc 12.3.0 + boost 1.83.0) |
結果 |
AC
|
実行時間 | 200 ms / 2,000 ms |
コード長 | 5,908 bytes |
コンパイル時間 | 2,906 ms |
コンパイル使用メモリ | 224,492 KB |
実行使用メモリ | 26,664 KB |
最終ジャッジ日時 | 2024-09-24 10:52:55 |
合計ジャッジ時間 | 6,381 ms |
ジャッジサーバーID (参考情報) |
judge1 / judge2 |
(要ログイン)
テストケース
テストケース表示入力 | 結果 | 実行時間 実行使用メモリ |
---|---|---|
testcase_00 | AC | 2 ms
6,816 KB |
testcase_01 | AC | 2 ms
6,944 KB |
testcase_02 | AC | 1 ms
6,944 KB |
testcase_03 | AC | 2 ms
6,940 KB |
testcase_04 | AC | 3 ms
6,944 KB |
testcase_05 | AC | 15 ms
6,940 KB |
testcase_06 | AC | 199 ms
21,684 KB |
testcase_07 | AC | 192 ms
21,504 KB |
testcase_08 | AC | 195 ms
21,632 KB |
testcase_09 | AC | 191 ms
21,756 KB |
testcase_10 | AC | 3 ms
6,944 KB |
testcase_11 | AC | 12 ms
6,944 KB |
testcase_12 | AC | 148 ms
22,912 KB |
testcase_13 | AC | 144 ms
22,852 KB |
testcase_14 | AC | 82 ms
26,644 KB |
testcase_15 | AC | 80 ms
26,664 KB |
testcase_16 | AC | 101 ms
24,112 KB |
testcase_17 | AC | 200 ms
21,632 KB |
testcase_18 | AC | 195 ms
21,696 KB |
ソースコード
#include <bits/stdc++.h> #pragma GCC target("avx2") #pragma GCC optimize("O3") #pragma GCC optimize("unroll-loops") #define ll long long #define ALL(a) (a).begin(),(a).end() #define rep(i,n) for(int i=0;i<(n);i++) #define rrep(i,n) for(int i=n-1;i>=0;i--) #define fi first #define se second #define pb push_back #define Pii pair<int,int> #define Pll pair<long long,long long> #define fout(num) cout << fixed << setprecision(20) << (num) << endl template<typename T1,typename T2> inline void chmin(T1 &a,T2 b){if(a>b) a=b;} template<typename T1,typename T2> inline void chmax(T1 &a,T2 b){if(a<b) a=b;} //vector<vector<ll>> dp(n,vector<ll>(n)) //2-dim:vector<vector<Type>> vv(n, vector<Type>(m, d)); //3-dim:vector<vector<vector<Type>>> vvv(n, vector<vector<Type>>(m, vector<Type>(l, d))); using namespace std; template <class Abel> struct BIT { vector<Abel> dat[2]; Abel UNITY_SUM = 0; // to be set /* [1, n] */ BIT(int n) { init(n); } void init(int n) { for (int iter = 0; iter < 2; ++iter) dat[iter].assign(n + 1, UNITY_SUM); } /* a is 1-indexed */ inline void sub_add(int p, int a, Abel x) { for (int i = a; i < (int)dat[p].size(); i += i & -i) dat[p][i] = dat[p][i] + x; } inline void add(int a, int b, Abel x) { sub_add(0, a, x * -(a - 1)); sub_add(1, a, x); sub_add(0, b, x * (b - 1)); sub_add(1, b, x * (-1)); } /* [1, a], a is 1-indexed */ inline Abel sub_sum(int p, int a) { Abel res = UNITY_SUM; for (int i = a; i > 0; i -= i & -i) res = res + dat[p][i]; return res; } inline Abel sum(int a, int b) { return sub_sum(0, b - 1) + sub_sum(1, b - 1) * (b - 1) - sub_sum(0, a - 1) - sub_sum(1, a - 1) * (a - 1); } /* debug */ void print() { for (int i = 1; i < (int)dat[0].size(); ++i) cout << sum(i, i + 1) << ","; cout << endl; } }; struct HL_decomposition{ private: int n; vector<vector<int>> G; vector<int> sz, par; // 部分木のサイズ,親頂点 vector<int> root; // 頂点が属するHeavy集合で,最も根に近い頂点 vector<int> in, out; // 頂点のEuler Tour上での始点/終点 // 部分木のサイズを取得し,0番目の子へのパスがHeavyにする void dfs_size(int v, int pre){ sz[v] = 1; par[v] = pre; for(auto &u:G[v]){ if(u == pre) continue; dfs_size(u, v); sz[v] += sz[u]; if(sz[u] > sz[G[v][0]]){ swap(u, G[v][0]); } } } // パスを構築 void dfs_path(int v, int pre, int &num){ in[v] = num; num++; for(auto u:G[v]){ if(u == pre) continue; root[u] = (u==G[v][0] ? root[v] : u); dfs_path(u, v, num); } out[v] = num; } public: // 初期化 HL_decomposition(vector<vector<int>> _G){ G = _G; n = (int)G.size(); sz.resize(n); par.assign(n, -1); in.assign(n, -1); out.assign(n, -1); root.assign(n, -1); dfs_size(0, -1); root[0] = 0; int tmp = 0; dfs_path(0, -1, tmp); } inline int get_inpos(int v){ return in[v]; } inline int get_outpos(int v){ return out[v]; } inline int get_subtree_size(int v){ return sz[v]; } // 最近共通祖先を求める.圧縮後の高さは高々log(n)なので,同じ所に入るまで愚直に見ればよい. int lca(int u, int v){ int ru = root[u], rv = root[v]; while(root[u]!=root[v]){ if(in[ru] > in[rv]){ u = par[u]; ru = root[u]; }else{ v = par[v]; rv = root[v]; } } if(in[u]>in[v]) return v; else return u; } // クエリ処理を行う.事前にサイズnのセグ木などを宣言する. // 部分木に対するクエリ処理.例:hl.query(v, [&](int l, int r){seg.update(l, r, x);}) void query_subtree(int v, const function<void(int,int)> &func){ func(in[v], out[v]); } // パスに対するクエリ処理.例:hl.query(v, [&](int l, int r){ans+=seg.query(l,r);}) void query_path(int u, int v, const function<void(int,int)> &func){ int ru = root[u], rv = root[v]; while(root[u]!=root[v]){ if(in[u] > in[v]){ func(in[ru], in[u]+1); u = par[u]; ru = root[u]; }else{ func(in[rv], in[v]+1); v = par[v]; rv = root[v]; } } if(in[u]>in[v]) swap(u, v); func(in[u], in[v]+1); } void query_nodes_path(int u, int v, const function<void(int,int)> &func){ while (true) { if (in[u] > in[v]) swap(u, v); func(max(in[root[v]], in[u]), in[v]); if (root[u] != root[v]) v = par[root[v]]; else break; } } }; void solve() { int n; cin>>n; vector<vector<int>> G(n); rep(i,n-1){ int u,v; cin>>u>>v; u--; v--; G[u].pb(v); G[v].pb(u); } HL_decomposition hld(G); BIT<long long> bit(n+1); ll res = 0; int Q;cin>>Q; while(Q--){ int a,b; cin>>a>>b; a--; b--; hld.query_nodes_path(a,b,[&](int l,int r){ bit.add(l+1, r+2, 1); res += bit.sum(l+1, r+2);}); } cout<<res<<endl; } signed main() { std::cin.tie(nullptr); std::ios_base::sync_with_stdio(false); solve(); return 0; } // g++ main.cpp -std=c++17 -o a.out && ./a.out