結果
| 問題 |
No.399 動的な領主
|
| コンテスト | |
| ユーザー |
|
| 提出日時 | 2022-11-16 23:09:16 |
| 言語 | C++14 (gcc 13.3.0 + boost 1.87.0) |
| 結果 |
WA
|
| 実行時間 | - |
| コード長 | 3,791 bytes |
| コンパイル時間 | 1,862 ms |
| コンパイル使用メモリ | 125,156 KB |
| 実行使用メモリ | 64,640 KB |
| 最終ジャッジ日時 | 2024-09-17 17:35:58 |
| 合計ジャッジ時間 | 7,384 ms |
|
ジャッジサーバーID (参考情報) |
judge3 / judge2 |
(要ログイン)
| ファイルパターン | 結果 |
|---|---|
| other | AC * 4 WA * 15 |
ソースコード
#include <algorithm>
#include <bit>
#include <bitset>
#include <cmath>
#include <cstdint>
#include <iomanip>
#include <iostream>
#include <map>
#include <queue>
#include <set>
#include <stack>
#include <vector>
#define rep(i, l, r) for(ll i = l; i <= r; i++)
static const int WH = 0;
static const int GR = 1;
static const int BL = 2;
using namespace std;
using ll = long long;
using ull = unsigned long long;
static const ll ll_INF = 1e18;
static const ll MOD = 998244353;
void chmin(ll &a, ll b) { a = min(a, b); }
struct LCA {
vector<int> height;
vector<vector<int>> anc;
vector<vector<int>> linked;
vector<ll> cnt;
vector<ll> incr;
int root;
int vertex_num;
LCA(int N, int root_vertex) {
vertex_num = N;
height = vector<int>(N + 5, -1);
anc = vector<vector<int>>(N + 5, vector<int>(100, -1));
linked = vector<vector<int>>(N + 5);
cnt = vector<ll>(N + 5, -1);
incr = vector<ll>(N + 5, 0);
root = root_vertex;
}
void add_edge(int u, int v) {
linked[u].push_back(v);
linked[v].push_back(u);
}
ll find_cnt(int u) {
if(cnt[u] != -1) return cnt[u];
cnt[u] = 0;
cnt[u] += incr[u];
for(int x:linked[u]){
if(x == find_anc(u,1)) continue;
cnt[u] += find_cnt(x);
}
return cnt[u];
}
void pass(int u, int v) {
int ca = find_common_anc(u, v);
incr[u]++;
incr[v]++;
incr[ca]--;
if(ca != root) {
incr[find_anc(ca, 1)]--;
}
}
ll solve() {
ll ans = 0;
for(int i = 1; i <= vertex_num; i++) {
ans += find_cnt(i) * (find_cnt(i) + 1) / 2;
}
return ans;
}
void find_height() {
queue<int> q;
q.push(root);
height[root] = 0;
while(q.size()) {
int nv = q.front();
q.pop();
for(int x : linked[nv]) {
if(height[x] == -1) {
height[x] = height[nv] + 1;
q.push(x);
anc[x][0] = nv;
}
}
}
}
int find_anc_sub(int u, int p) { // 頂点uの2^p前の頂点を求める.
// cout << "sub " << u << " " << p << " " << anc[u][p] << endl;
if(anc[u][p] != -1)
return anc[u][p];
if(height[u] < pow_ll(2, p))
return -1;
anc[u][p] = find_anc_sub(find_anc_sub(u, p - 1), p - 1);
return anc[u][p];
}
int find_anc(int u, int dis) {
int var = 1;
int p = 0;
while(dis) {
if(dis & 1)
u = find_anc_sub(u, p);
p += 1;
dis >>= 1;
}
return u;
}
int find_common_anc(int u, int v) {
if(u == v)
return u;
int left = 0;
int right = min(height[u], height[v]);
while(right - left > 1) {
int mid = (left + right) / 2;
if(find_anc(u, height[u] - mid) == find_anc(v, height[v] - mid))
left = mid;
else
right = mid;
}
return find_anc(u, height[u] - left);
}
ll pow_ll(ll u, ll v) { // u^v
ll ans = 1;
while(v > 0) {
if(v & 1)
ans *= u;
v >>= 1;
u *= u;
}
return ans;
}
};
int main() {
int N;
cin >> N;
LCA lca(N, 1);
rep(i, 1, N - 1) {
int u, v;
cin >> u >> v;
lca.add_edge(u, v);
}
lca.find_height();
int Q;
cin >> Q;
rep(i, 1, Q) {
int a, b;
cin >> a >> b;
lca.pass(a, b);
}
//lca.find_cnt();
cout << lca.solve() << endl;
return 0;
}