#include using namespace std; // Basic #define ll int64_t const ll INF=(1LL<<60); #define p_ii pair #define p_dd pair #define p_is pair #define p_si pair #define m_ii(v) map v; #define m_si(v) map 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 par; // par[i] : iの親の番号 vector 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::max(); function fx = [](ll x1, ll x2) -> ll { return min(x1, x2); }; ll n; vector 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 v(n) // int #define vec_(v,n,m) vector v(n,m) // int 初期条件あり #define vec64(v,n) vector v(n) // int64_t #define vec64_(v,n,m) vector v(n,m) // int64_t 初期条件あり #define vecd(v,n) vector v(n) // double #define vecc(v,n) vector v(n) // char #define vecs(v,n) vector v(n) // string #define vece(v) vector v; // int 空 #define vecec(v) vector v; // char 空 #define vecp(v,n) vector v(n) // pair #define vec2i(v,h,w) vector> v(h,vector(w)) // 二次元配列 int #define vec2c(v,h,w) vector> v(h,vector(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] 0) { if (n & 1) res = res * a % MOD; a = a * a % MOD; n >>= 1; } return res;} // a^n(MODで割った余り) vector n_sin(ll x,ll n){ vector 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 prime_p(ll x){ vector 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 prime_a(ll x){ vector 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 prime(ll x){ vector> 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;} // 素因数分解(…の~乗) // others #define under(n) cout<>; using wGraph = vector>; 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); } }