結果

問題 No.399 動的な領主
コンテスト
ユーザー yt142857
提出日時 2026-05-08 23:29:02
言語 C++23
(gcc 15.2.0 + boost 1.89.0)
コンパイル:
g++-15 -O2 -lm -std=c++23 -Wuninitialized -DONLINE_JUDGE -o a.out _filename_
実行:
./a.out
結果
WA  
実行時間 -
コード長 8,622 bytes
記録
記録タグの例:
初AC ショートコード 純ショートコード 純主流ショートコード 最速実行時間
コンパイル時間 3,733 ms
コンパイル使用メモリ 361,868 KB
実行使用メモリ 58,704 KB
最終ジャッジ日時 2026-05-08 23:29:18
合計ジャッジ時間 10,709 ms
ジャッジサーバーID
(参考情報)
judge1_0 / judge3_0
このコードへのチャレンジ
(要ログイン)
ファイルパターン 結果
other AC * 16 WA * 3
権限があれば一括ダウンロードができます

ソースコード

diff #
raw source code

#include <bits/stdc++.h>
using namespace std;
#define Min(x) *min_element(x.begin(),x.end())
#define Max(x) *max_element(x.begin(),x.end())
#define rep(i, n) for (int i = 0; i < (int)(n); i++)
#define range(i,a,b,c) for(int i=a;i<(int)(b);i+=c)
using ll = long long;
using ch = char;
using str = string;
using vll = vector<ll>;
using vch = vector<ch>;
using vvll = vector<vll>;
using sll = set<ll>;
const ll mod998 = 998244353;
const ll mod107 = 1e9+7;
const ll using_mod = mod998;
vll erat(2e6,-1);
vll mobius(2e6,1);
void comp_erat(){
  erat[1] = 1;
  for(int i=2;i<2e6;i++){
    if(erat[i]==-1){
      for(int j=i;j<2e6;j+=i){
        if(j%(i*i)==0) mobius[j] = 0;
        else mobius[j] *= -1;
        if(erat[j]==-1) erat[j] = i;
      }
    }
  }
}
template <class T>
vector<T> fast_zeta(vector<T> &f){
  int len_f = f.size();
  vector<T> F = f;
  for(int i=2;i<len_f;i++){
    if(erat[i]==i){
      for(int j=(len_f-1)/i;j>0;j--){
        F[j] += F[j*i];
      }
    }
  }
  return F;
}
template <class T>
vector<T> fast_mobius(vector<T> &F){
  int len_F = F.size();
  vector<T> f = F;
  for(int i=2;i<len_F;i++){
    if(erat[i]==i){
      for(int j=0;j<=(len_F-1)/i;j++){
        f[j] -= f[j*i];
      }
    }
  }
  return f;
}

vll PF(ll num){
  vll re;
  while(num!=1){
    re.push_back(erat[num]);
    num = num / erat[num];
  }
  return re;
}
vll fact_mod = {1};
void comp_fact(const ll &mod=using_mod){
  for(int i=0;i<1e6;i++){
    fact_mod.push_back((fact_mod[i]*(i+1))%mod);
  }
}
ll pow_mod(const ll &a,const ll &b,const ll &mod=using_mod){
  vll amari;
  amari.push_back(a%mod);
  int count = 0;
  ll count_two = 2;
  while(count_two<=b){
    amari.push_back((amari[count]*amari[count])%mod);
    count += 1;
    count_two *= 2;
  }
  ll re = 1;
  for (int i=0;i<(int)amari.size();i++){
    if (b>>i & 1){
      re = (re*amari[i])%mod;
    }
  }
  return re;
}
ll inv(ll a,ll m=using_mod) {
  ll b = m, u = 1, v = 0;
  while (b) {
    ll t = a / b;
    a -= t * b; swap(a, b);
    u -= t * v; swap(u, v);
  }
  u %= m;
  if (u < 0) u += m;
  return u;
}
ll nCr(const ll &n,const ll &r,const ll &mod=using_mod){
  if (n < r) return 0;
  ll one = fact_mod[n];
  ll two = (fact_mod[n-r]*fact_mod[r])%mod;
  ll re = (one*inv(two,mod))%mod;
  return re;
}
ll _GCM(ll n,ll m){
  if(m>n) swap(n,m);
  if(m == 0){
    return n;
  }
  else{
    return _GCM(m,n%m);
  }
}
ll GCM(ll n,ll m){
  if(n<0) n*=-1;
  if(m<0) m*=-1;
  return _GCM(n,m);
}
vll ruiseki(const vll &a){
  vll re(a.size()+1);
  for(int i=0;i<(int)a.size();i++){
    re[i+1] = re[i]+a[i];
  }
  return re;
}
ll bisect_left(const vll &s,const ll &a){
  auto itr = lower_bound(s.begin(), s.end(), a);
  ll re = itr - s.begin();
  return re;
}
ll bisect_right(const vll &s,const ll &a){
  auto itr = lower_bound(s.begin(), s.end(), a+1);
  ll re = itr - s.begin();
  return re;
}


void print(vector<int> s){
  cout << '[';
  for(int i:s){
    cout << i << ' ';
  }
  cout << ']';
  cout << endl;
}
void print(vector<pair<int,int>> s){
  cout << '[';
  for(pair<int,int> i:s){
    cout << '{' << i.first << ' ' << i.second << '}' << ' ';
  }
  cout << ']';
  cout << endl;
}

struct HLD{
  int n;
  vector<vector<int>> tree;
  vector<int> childs_num;
  vector<int> parents;
  vector<int> vertex;
  vector<int> id;
  vector<int> head;
  vector<int> depth;
  
  //部分木サイズを計算
  void comp_childs_num(int node){
    int now = 0;
    for(int nei:tree[node]){
      comp_childs_num(nei);
      now += childs_num[nei];
    }
    childs_num[node] = now + 1;
  }
  //heavy child優先のdfs
  void dfs(int node,int now_head){
    head[node] = now_head;
    vertex.push_back(node);
    pair<int,int> maxi(-1,-1);
    for(int nei:tree[node]){
      maxi = max(maxi,{childs_num[nei],nei});
    }
    int heavy_child = maxi.second;
    if(heavy_child != -1){
      int heavy_child = maxi.second;
      dfs(heavy_child,now_head);
      for(int nei:tree[node]){
        if(nei!=heavy_child){
          dfs(nei,nei);
        }
      }
    }
  }
  //コンストラクタ
  HLD(int _n,vector<pair<int,int>> s){
    n = _n;
    tree.assign(n,vector<int>(0));
    
    id.assign(n,0);
    head.assign(n,0);
    depth.assign(n,0);
    parents.assign(n,-1);
    childs_num.assign(n,-1);
    
    vector<vector<int>> graph(n,vector<int>(0));
    for(pair<int,int> i : s){
      graph[i.first].push_back(i.second);
      graph[i.second].push_back(i.first);
    }
    
    //根付き木の構築
    //depth.parentsをついでに計算
    deque<int> queue;
    queue.push_back(0);
    vector<bool> visited(n,false); 
    visited[0] = true;
    while(!queue.empty()){
      int now = queue.front();queue.pop_front();
      for(int nei:graph[now]){
        if(!visited[nei]){
          depth[nei] = depth[now] + 1;
          parents[nei] = now;
          tree[now].push_back(nei);
          visited[nei] = true;
          queue.push_back(nei);
        }
      }
    }
    
    //部分木サイズを計算
    comp_childs_num(0);
    
    //heavy_child優先のdfs
    //head,vertexを計算
    dfs(0,0);

    //idを計算
    for(int i=0;i<n;i++){
      id[vertex[i]] = i;
    }
  }
  
  int LCA(int u,int v){
    while(true){
      if(head[u] == head[v]){
        if(depth[u] < depth[v]){
          return u;
        }
        else{
          return v;
        }
      }
      if(id[u] < id[v]){
        v = parents[head[v]];
      }
      else{
        u = parents[head[u]];
      }
    }
  }
  
  int dis(int u,int v){
    int lca = LCA(u,v);
    return depth[u]-depth[lca] + depth[v]-depth[lca];
  }
  
  vector<int> to_path(){
    return vertex;
  }
  
  vector<pair<int,int>> use_path(int u,int v){
    vector<pair<int,int>> re;
    while(true){
      if(head[u] == head[v]){
        re.push_back({min(id[u],id[v]) ,max(id[u],id[v]) + 1});
        return re;
      }
      if(id[u] < id[v]){
        re.push_back({min(id[v],id[head[v]]) ,max(id[v],id[head[v]]) + 1});
        v = parents[head[v]];
      }
      else{
        re.push_back({min(id[u],id[head[u]]) ,max(id[u],id[head[u]]) + 1});
        u = parents[head[u]];
      }
    }

  }
};


using S = pair<ll,int>;
using F = int;
S op(S a,S b){
  S re = {a.first+b.first,a.second+b.second};
  return re;
}
S e(){
  return {0,0};
}
S mapping(F a,S b){
  b.first += b.second  * a;
  return b;
}
F composition(F a,F b){
  return a+b;
}
F id(){
  return 0;
}
template <class S,
          S (*op)(S, S),
          S (*e)(),
          class F,
          S (*mapping)(F, S),
          F (*composition)(F, F),
          F (*id)()>
struct LazySegTree{
  int _n,size,log_;
  vector<S> data;
  vector<F> lazy;
  LazySegTree(int num){
    log_ = 0;
    size = 1;
    while(size < num){
      log_ ++;
      size *= 2;
    }
    data.assign(2*size, e());
    lazy.assign(2*size, id());
  }
  void push(int num){
    data[num] = mapping(lazy[num],data[num]);
    if(num < size){
      lazy[num*2] = composition(lazy[num],lazy[num*2]);
      lazy[num*2+1] = composition(lazy[num],lazy[num*2+1]);
    }
    lazy[num] = id();
  }
  void push_up(int num){
    if(num < size){
      data[num] = op(data[num*2],data[num*2+1]);
    }
  }
  void set(int num,S s) {
    num += size;
    for(int i=log_;i >= 1;i--) push(num >> i);
    data[num] = s;
    for(int i=1;i <= log_;i++) push_up(num >> i);
  }
  S _prod(int nl,int nr,int gl,int gr,int node){
    push(node);
    if(nr <= gl || gr <= nl) return e();
    else if(gl <= nl && nr <= gr){
      return data[node];
    }
    else{
      int mid = (nl+nr) / 2;
      S re = op(_prod(nl,mid,gl,gr,node*2),_prod(mid,nr,gl,gr,node*2+1));
      push_up(node);
      return re;
    }
  }
  S prod(int l,int r){
    return _prod(0,size,l,r,1);
  }
  void _apply(int nl,int nr,int gl,int gr,int node,F f){
    push(node);
    if(nr <= gl || gr <= nl){}
    else if(gl <= nl && nr <= gr){
      lazy[node] = f;
      push(node);
    }
    else{
      int mid = (nl+nr) / 2;
      _apply(nl,mid,gl,gr,node*2,f);_apply(mid,nr,gl,gr,node*2+1,f);
      push_up(node);
    }
  }
  void apply(int l,int r,F f){
    _apply(0,size,l,r,1,f);
  }
};


int main(){
  int n;cin >> n;
  vector<pair<int,int>> edgs;
  rep(i,n-1){
    int a,b;cin >> a >> b;a--;b--;
    edgs.push_back({a,b});
  }
  HLD hld(n,edgs);
  LazySegTree<S,op,e,F,mapping,composition,id> seg(n);
  rep(i,n){
    seg.set(i,{1,1});
  }
  int q;cin >> q;
  ll ans = 0;
  rep(i,q){
    int a,b;cin >> a >> b;a--;b--;
    for(pair<int,int> j:hld.use_path(a,b)){
      pair<int,int> now = seg.prod(j.first,j.second);
      ans += now.first;
      seg.apply(j.first,j.second,1);
    }
  }
  cout << ans << endl;
}
0