結果

問題 No.1637 Easy Tree Query
ユーザー kusaf_kusaf_
提出日時 2021-08-19 17:00:38
言語 C++14
(gcc 12.3.0 + boost 1.83.0)
結果
AC  
実行時間 275 ms / 2,000 ms
コード長 10,171 bytes
コンパイル時間 2,017 ms
コンパイル使用メモリ 179,068 KB
実行使用メモリ 17,280 KB
最終ジャッジ日時 2024-10-12 17:44:21
合計ジャッジ時間 11,568 ms
ジャッジサーバーID
(参考情報)
judge5 / judge4
このコードへのチャレンジ
(要ログイン)

テストケース

テストケース表示
入力 結果 実行時間
実行使用メモリ
testcase_00 AC 6 ms
9,344 KB
testcase_01 AC 6 ms
9,472 KB
testcase_02 AC 264 ms
12,544 KB
testcase_03 AC 6 ms
9,344 KB
testcase_04 AC 63 ms
11,008 KB
testcase_05 AC 218 ms
10,496 KB
testcase_06 AC 143 ms
10,368 KB
testcase_07 AC 79 ms
9,600 KB
testcase_08 AC 51 ms
10,752 KB
testcase_09 AC 161 ms
11,904 KB
testcase_10 AC 102 ms
10,112 KB
testcase_11 AC 232 ms
12,160 KB
testcase_12 AC 227 ms
11,520 KB
testcase_13 AC 40 ms
10,240 KB
testcase_14 AC 101 ms
11,904 KB
testcase_15 AC 212 ms
12,288 KB
testcase_16 AC 156 ms
12,544 KB
testcase_17 AC 66 ms
10,240 KB
testcase_18 AC 200 ms
10,624 KB
testcase_19 AC 195 ms
10,880 KB
testcase_20 AC 240 ms
11,520 KB
testcase_21 AC 120 ms
11,136 KB
testcase_22 AC 245 ms
12,672 KB
testcase_23 AC 65 ms
10,368 KB
testcase_24 AC 96 ms
11,136 KB
testcase_25 AC 222 ms
10,624 KB
testcase_26 AC 245 ms
11,648 KB
testcase_27 AC 275 ms
12,544 KB
testcase_28 AC 164 ms
10,624 KB
testcase_29 AC 189 ms
11,392 KB
testcase_30 AC 59 ms
11,264 KB
testcase_31 AC 180 ms
9,472 KB
testcase_32 AC 100 ms
10,624 KB
testcase_33 AC 210 ms
10,240 KB
testcase_34 AC 76 ms
17,280 KB
権限があれば一括ダウンロードができます

ソースコード

diff #

#include <bits/stdc++.h>
using namespace std;
// Basic
#define ll int64_t
const ll INF=(1LL<<60);
#define p_ii pair<ll,ll>
#define p_dd pair<double,double>
#define p_is pair<ll,string>
#define p_si pair<string,ll>
#define m_ii(v) map<ll,ll> v;
#define m_si(v) map<string,ll> v;
#define fi first
#define sc second
#define mp make_pair
struct UnionFind {
  /*
    unite(x,y) : x と y の木を併合
    same(x,y) : x と y の属する木が同じなら true
  */
    vector<int> par; // par[i] : iの親の番号
    vector<int> usiz; // usiz[i] : iを含む連結成分のサイズ
    UnionFind(int n) : par(n),usiz(n) {
        for(int i = 0; i < n; i++){
             par[i] = i;
             usiz[i] = 1;
        }
    }
    int root(int x) {
        if (par[x] == x) return x;
        return par[x] = root(par[x]);
    }
    void unite(int x, int y) {
        int rx = root(x);
        int ry = root(y);
        if (rx == ry) return;
        if (usiz[rx] > usiz[ry]){
          par[ry] = rx;
          usiz[rx] += usiz[ry];
        } else {
          par[rx] = ry;
          usiz[ry] += usiz[rx];
        }
        //par[rx] = ry;
    }
    bool same(int x, int y) {
        int rx = root(x);
        int ry = root(y);
        return rx == ry;
    }
    int siz(int x){ return usiz[root(x)];}
};
struct RMQ {
  /*
    set(ll i, ll x), build(): i番目の要素をxにセット。まとめてセグ木を構築する。O(n)
    update(i,x): i 番目の要素を x に更新。O(log(n))
    query(a,b): [a,b) での最小の要素を取得。O(log(n))
    find_rightest(a,b,x): [a,b) で x以下の要素を持つ最右位置を求める。O(log(n))
    find_leftest(a,b,x): [a,b) で x以下の要素を持つ最左位置を求める。O(log(n))
  */
    const ll e = numeric_limits<ll>::max();
    function<ll(ll, ll)> fx = [](ll x1, ll x2) -> ll { return min(x1, x2); };
    ll n;
    vector<ll> dat;
    RMQ(ll n_) : n(), dat(n_ * 4, e) {
        ll x = 1;
        while (n_ > x) {
            x *= 2;
        }
        n = x;
    }
    void set(ll i, ll x) { dat[i + n - 1] = x; }
    void build() {
        for (ll k = n - 2; k >= 0; k--) dat[k] = fx(dat[2 * k + 1], dat[2 * k + 2]);
    }
    void update(ll i, ll x) {
        i += n - 1;
        dat[i] = x;
        while (i > 0) {
            i = (i - 1) / 2;
            dat[i] = fx(dat[i * 2 + 1], dat[i * 2 + 2]);
        }
    }
    // the minimum element of [a,b)
    ll query(ll a, ll b) { return query_sub(a, b, 0, 0, n); }
    ll query_sub(ll a, ll b, ll k, ll l, ll r) {
        if (r <= a || b <= l) {
            return e;
        } else if (a <= l && r <= b) {
            return dat[k];
        } else {
            ll vl = query_sub(a, b, k * 2 + 1, l, (l + r) / 2);
            ll vr = query_sub(a, b, k * 2 + 2, (l + r) / 2, r);
            return fx(vl, vr);
        }
    }
    ll find_rightest(ll a, ll b, ll x) { return find_rightest_sub(a, b, x, 0, 0, n); }
    ll find_leftest(ll a, ll b, ll x) { return find_leftest_sub(a, b, x, 0, 0, n); }
    ll find_rightest_sub(ll a, ll b, ll x, ll k, ll l, ll r) {
        if (dat[k] > x || r <= a || b <= l) {  // 自分の値がxより大きい or [a,b)が[l,r)の範囲外ならreturn a-1
            return a - 1;
        } else if (k >= n - 1) {  // 自分が葉ならその位置をreturn
            return (k - (n - 1));
        } else {
            ll vr = find_rightest_sub(a, b, x, 2 * k + 2, (l + r) / 2, r);
            if (vr != a - 1) {  // 右の部分木を見て a-1 以外ならreturn
                return vr;
            } else {  // 左の部分木を見て値をreturn
                return find_rightest_sub(a, b, x, 2 * k + 1, l, (l + r) / 2);
            }
        }
    }
    ll find_leftest_sub(ll a, ll b, ll x, ll k, ll l, ll r) {
        if (dat[k] > x || r <= a || b <= l) {  // 自分の値がxより大きい or [a,b)が[l,r)の範囲外ならreturn b
            return b;
        } else if (k >= n - 1) {  // 自分が葉ならその位置をreturn
            return (k - (n - 1));
        } else {
            ll vl = find_leftest_sub(a, b, x, 2 * k + 1, l, (l + r) / 2);
            if (vl != b) {  // 左の部分木を見て b 以外ならreturn
                return vl;
            } else {  // 右の部分木を見て値をreturn
                return find_leftest_sub(a, b, x, 2 * k + 2, (l + r) / 2, r);
            }
        }
    }
};
// Loop
#define lp(i,n) for(ll i=0;i<n;i++)
#define lp_(i,n) for(ll i=0;i<=n;i++)    // 条件に=つき
#define lpp(i,n,m) for(ll i=n;i<m;i++)
#define lpp_(i,n,m) for(ll i=n;i<=m;i++)
// vector定義
#define _GLIBCXX_DEBUG
#define vec(v,n) vector<int> v(n)       // int
#define vec_(v,n,m) vector<int> v(n,m)  // int 初期条件あり
#define vec64(v,n) vector<ll> v(n)      // int64_t
#define vec64_(v,n,m) vector<ll> v(n,m) // int64_t 初期条件あり
#define vecd(v,n) vector<double> v(n)   // double
#define vecc(v,n) vector<char> v(n)     // char
#define vecs(v,n) vector<string> v(n)   // string
#define vece(v) vector<ll> v;           // int 空
#define vecec(v) vector<char> v;        // char 空
#define vecp(v,n) vector<p_ii> v(n)     // pair
#define vec2i(v,h,w) vector<vector<ll>> v(h,vector<ll>(w))    // 二次元配列 int
#define vec2c(v,h,w) vector<vector<char>> v(h,vector<char>(w))  // 二次元配列 char
// vector,string操作
#define vin(v) \
{\
  lp(i,v.size())\
    cin>>v[i];\
}                              // 入力
#define vini(v,n) \
{\
  lp(i,v.size())\
  {\
    lp(j,v.at(0).size())\
      v[i][j]=n;\
  }\
}                           // 二次元配列初期化
#define all(v) v.begin(),v.end()
#define si(v) int(v.size())                      // サイズ
#define back(v) v.back()                         // 最後の要素
#define sum(v) accumulate(all(v),0)              // 総和
#define sort(v) sort(all(v))                     // ソート
#define reverse(v) reverse(all(v))               // 反転
#define lower(v,x) lower_bound(all(v),x)-v.begin() // a[i]<xとなるiの個数
#define upper(v,x) upper_bound(all(v),x)-v.begin() // a[i]<=xとなるiの個数
#define cou(v,n) count(all(v),n)                 // n の出現回数を数える
#define pb(v,n) v.push_back(n)                   // 最後尾に n を追加
#define ins(v,i,n) v.insert(v.begin()+i,n)       // 場所を指定してv[i]に n を追加
#define del(v) v.pop_back()                      // 最後尾を削除
#define del0(v) v.erase(v.begin())               // 最初の要素v[0]を削除
#define del_(v,i) v.erase(v.begin()+i)           // 場所を指定してv[i]を削除
#define del__(v,i,j) v.erase(v.begin()+i,v.begin()+j+1)  // 範囲を指定してv[i]~v[j]を削除
#define sub(s,i,j) s.substr(i,j-i+1)             // 範囲を指定してs[i]~s[j]を取得【stringのみ】
// functions
const ll MOD=1000000007;
const int COMAX = 510000;
ll COMdp[100][100],fac[COMAX], finv[COMAX], inv[COMAX];
int wa(ll x){
  int sum=0;
  for(;x!=0;)
  {
    sum+=x%10;
    x/=10;
  }
  return sum;
}                  // 各位の和
int keta(ll x){
  int r=0;
  while(x!=0)
  {
    x/=10;
    r++;
  }
  return r;
}                // 桁数
void COMinit() {
    fac[0] = fac[1] = 1;
    finv[0] = finv[1] = 1;
    inv[1] = 1;
    for (int i = 2; i < COMAX; i++){
        fac[i] = fac[i - 1] * i % MOD;
        inv[i] = MOD - inv[MOD%i] * (MOD / i) % MOD;
        finv[i] = finv[i - 1] * inv[i] % MOD;
    }
}
ll COM_M(ll n, ll k){
    if (n < k) return 0;
    if (n < 0 || k < 0) return 0;
    return fac[n] * (finv[k] * finv[n - k] % MOD) % MOD;}          // nCk(MODで割った余り)← 適宜COMAX変更!!
ll COM(ll n, ll k){
    if(n==k) return COMdp[n][k] = 1;
    if(k==0) return COMdp[n][k] = 1;
    if(k==1) return COMdp[n][k] = n;
    if(COMdp[n][k]) return COMdp[n][k];
    return COMdp[n][k] = COM(n-1,k) + COM(n-1,k-1);}            // nCk(答えが2^64まで,余りは出さない)← 適宜COMdp変更!!
ll pow_M(ll a, ll n){
    ll res = 1;
    while (n > 0) {
        if (n & 1) res = res * a % MOD;
        a = a * a % MOD;
        n >>= 1;
    }
    return res;}          // a^n(MODで割った余り)
vector<ll> n_sin(ll x,ll n){
  vector<ll> r;
  while(x!=0)
  {
    pb(r,x%n);
    x=x-x%n;
    x/=n;
  }
  reverse(r);
  return r;}   // n進法
ll kiri(ll a,ll b){
  ll r=(a+b-1)/b;
  return r;
}            // 割り算(小数点以下切り上げ)
ll kai_M(ll n){
  ll r=1;
  lpp_(i,2,n)
  {
    r*=i;
    r%=MOD;
  }
  return r;}                // n!(MODで割った余り)
vector<ll> prime_p(ll x){
    vector<ll> pri;
    for(ll d=2;d*d<=x;d++)
    {
      if(x%d!=0)
        continue;
      ll ex=0;
      while(x%d==0)
      {
        ex++;
        x/=d;
      }
      pb(pri,ex);
    }
    if(x!=1)
      pb(pri,1);
    return pri;
  }      // 素因数分解(~乗の部分のみ)
vector<ll> prime_a(ll x){
    vector<ll> res;
    for (ll a=2;a*a<=x;a++)
    {
      if (x%a!=0) continue;
      while (x%a==0)
        x/= a;
      pb(res,a);
    }
    if (x != 1) pb(res,x);
    return res;
  }      // 素因数分解(素因数を返すだけ)
vector<p_ii> prime(ll x){
    vector<pair<ll, ll>> res;
    for (ll a=2;a*a<=x;a++)
    {
      if (x%a!=0) continue;
      ll ex=0;
      while (x%a==0)
      {
        ++ex;
        x /= a;
      }
      res.push_back({a, ex});
    }
    if (x != 1) res.push_back({x, 1});
    return res;}      // 素因数分解(…の~乗<pair>)
// others
#define under(n) cout<<fixed<<setprecision(n) // 小数点以下の桁数を指定
#define cout(n) cout<<n<<endl
#define en cout<<endl
#define Y cout("Yes")                         // "Yes"
#define N cout("No")                          // "No"
using Graph = vector<vector<int>>;
using wGraph = vector<vector<p_ii>>;

Graph g(200010);
vec64_(f,200010,1);

void dfs(ll v,ll p)
{
  for(auto nv:g[v]) if(nv!=p) dfs(nv,v);
  for(auto nv:g[v]) if(nv!=p) f[v]+=f[nv];
}

int main()
{
  ll n,q,r=0; cin>>n>>q;
  lp(i,n-1)
  {
    ll a,b; cin>>a>>b;
    a--; b--;
    pb(g[a],b);
    pb(g[b],a);
  }
  dfs(0,-1);
  lp(i,q)
  {
    ll a,b; cin>>a>>b;
    a--;
    r+=f[a]*b;
    cout(r);
  }

}
0