#pragma comment(linker,"/STACK:100000000,100000000")

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <string>
#include <cstring>
#include <vector>
#include <stack>
#include <cmath>
#include <map>
#include <stack>
#include <set>
#include <iomanip>
#include <queue>
#include <map>
#include <functional>
#include <memory.h>
#include <list>
#include <sstream>
#include <ctime>
#include <climits>
#include <bitset>

using namespace std;

/* Constants begin */
const long long inf = 1e18+7;
const long long mod = 1e9+7;
const double eps = 1e-9;
const double PI = 2*acos(0.0);
const double E = 2.71828;
/* Constants end */

/* Defines begin */
#define pb push_back
#define mp make_pair
#define ll long long
#define double long double
#define F first
#define S second
#define all(a) (a).begin(), (a).end()
#define forn(i,n) for (ll (i)=0;(i)<(ll)(n);(i)++)
/* Defines end */

vector< vector< pair<ll,ll> > > g;
ll up[100005][18];
ll tin[100005], tout[100005], timer = 0;
ll add[100005];
ll ans[100005];

ll get(ll v, ll now, ll p = -1) {
    now += add[v];
    for(ll i=0;i<g[v].size();i++) {
        ll to = g[v][i].F;
        if(to != p) {
            ll num = get(to,now,v);
            ans[g[v][i].S] += num-now;
            now += num-now;
        }
    }
    return now;
}

void dfs(ll v, ll p = 1) {
    tin[v] = timer++;
    up[v][0] = p;
    for(ll i=1;i<=17;i++)
     up[v][i] = up[up[v][i-1]][i-1];
    for(ll i=0;i<g[v].size();i++) {
        ll to = g[v][i].F;
        if(p != to) dfs(to,v);
    }
    tout[v] = timer++;
}

ll line(ll v, ll u) {
    return tout[v] >= tout[u] && tin[v] <= tin[u];
}

ll lca(ll v, ll u) {
    if(line(v,u)) return v;
    if(line(u,v)) return u;
    for(ll i=17;i>=0;i--)
     if(!line(up[v][i],u))
      v = up[v][i];
    return up[v][0];
}

int main(void) {
    #ifndef ONLINE_JUDGE
        freopen("input.txt","rt",stdin);
        freopen("output.txt","wt",stdout);
    #endif
    ll n; cin >> n;
    g.resize(n+1);
    for(ll i=0;i<n-1;i++) {
        ll x, y; cin >> x >> y;
        g[x].pb(mp(y,i)); g[y].pb(mp(x,i));
    }
    dfs(1);
    ll m; cin >> m;
    for(ll i=0;i<m;i++) {
        ll x, y; cin >> x >> y;
        add[x]++; add[y]++;
        ll z = lca(x,y);
        if(z == x || z == y) add[z]--; else
        add[z] -= 2;
    }
    get(1,0);
    for(ll i=0;i<n-1;i++)
     cout << ans[i] << " ";
    cout << endl;
    return 0;
}


#pragma comment(linker,"/STACK:100000000,100000000")

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <string>
#include <cstring>
#include <vector>
#include <stack>
#include <cmath>
#include <map>
#include <stack>
#include <set>
#include <iomanip>
#include <queue>
#include <map>
#include <functional>
#include <memory.h>
#include <list>
#include <sstream>
#include <ctime>
#include <climits>
#include <bitset>

using namespace std;

/* Constants begin */
const long long inf = 1e18+7;
const long long mod = 1e9+7;
const double eps = 1e-9;
const double PI = 2*acos(0.0);
const double E = 2.71828;
/* Constants end */

/* Defines begin */
#define pb push_back
#define mp make_pair
#define ll long long
#define double long double
#define F first
#define S second
#define all(a) (a).begin(), (a).end()
#define forn(i,n) for (ll (i)=0;(i)<(ll)(n);(i)++)
/* Defines end */

vector< vector< pair<ll,ll> > > g;
ll up[100005][18];
ll tin[100005], tout[100005], timer = 0;
ll ans[100005];
multiset<ll> S;
vector<ll> add[100005], del[100005];

void get(ll v, ll p = -1) {
    for(ll i=0;i<add[v].size();i++)
     S.insert(add[v][i]);
    for(ll i=0;i<del[v].size();i++)
     S.erase(S.lower_bound(del[v][i]));
    for(ll i=0;i<g[v].size();i++) {
        ll to = g[v][i].F;
        if(to != p) {
            ll num = S.size();
            get(to,v);
            ans[g[v][i].S] += num-S.size();
        }
    }
}

void dfs(ll v, ll p = 1) {
    tin[v] = timer++;
    up[v][0] = p;
    for(ll i=1;i<=17;i++)
     up[v][i] = up[up[v][i-1]][i-1];
    for(ll i=0;i<g[v].size();i++) {
        ll to = g[v][i].F;
        if(p != to) dfs(to,v);
    }
    tout[v] = timer++;
}

ll line(ll v, ll u) {
    return tout[v] >= tout[u] && tin[v] <= tin[u];
}

ll lca(ll v, ll u) {
    if(line(v,u)) return v;
    if(line(u,v)) return u;
    for(ll i=17;i>=0;i--)
     if(!line(up[v][i],u))
      v = up[v][i];
    return up[v][0];
}

int main(void) {
    #ifndef ONLINE_JUDGE
        freopen("input.txt","rt",stdin);
        freopen("output.txt","wt",stdout);
    #endif
    ll n; cin >> n;
    g.resize(n+1);
    for(ll i=0;i<n-1;i++) {
        ll x, y; cin >> x >> y;
        g[x].pb(mp(y,i)); g[y].pb(mp(x,i));
    }
    dfs(1);
    ll m; cin >> m;
    for(ll i=0;i<m;i++) {
        ll x, y; cin >> x >> y;
        ll z = lca(x,y);
        add[z].pb(x); add[z].pb(y);
        del[x].pb(x); del[y].pb(y);
    }
    get(1);
    for(ll i=0;i<n-1;i++)
     cout << ans[i] << " ";
    cout << endl;
    return 0;
}


#pragma comment(linker,"/STACK:100000000,100000000")

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <string>
#include <cstring>
#include <vector>
#include <stack>
#include <cmath>
#include <map>
#include <stack>
#include <set>
#include <iomanip>
#include <queue>
#include <map>
#include <functional>
#include <memory.h>
#include <list>
#include <sstream>
#include <ctime>
#include <climits>
#include <bitset>

using namespace std;

/* Constants begin */
const long long inf = 1e18+7;
const long long mod = 1e9+7;
const double eps = 1e-9;
const double PI = 2*acos(0.0);
const double E = 2.71828;
/* Constants end */

/* Defines begin */
#define pb push_back
#define mp make_pair
#define ll long long
#define double long double
#define F first
#define S second
#define all(a) (a).begin(), (a).end()
#define forn(i,n) for (ll (i)=0;(i)<(ll)(n);(i)++)
/* Defines end */

vector< vector< pair<ll,ll> > > g;
ll up[100005][18];
ll tin[100005], tout[100005], timer = 0;
ll add[100005];
ll ans[100005];

ll get(ll v, ll now, ll p = -1) {
    now += add[v];
    for(ll i=0;i<g[v].size();i++) {
        ll to = g[v][i].F;
        if(to != p) {
            ll num = get(to,now,v);
            ans[g[v][i].S] += num-now;
            now = num;
        }
    }
    return now;
}

void dfs(ll v, ll p = 1) {
    tin[v] = timer++;
    up[v][0] = p;
    for(ll i=1;i<=17;i++)
     up[v][i] = up[up[v][i-1]][i-1];
    for(ll i=0;i<g[v].size();i++) {
        ll to = g[v][i].F;
        if(p != to) dfs(to,v);
    }
    tout[v] = timer++;
}

ll line(ll v, ll u) {
    return tout[v] >= tout[u] && tin[v] <= tin[u];
}

ll lca(ll v, ll u) {
    if(line(v,u)) return v;
    if(line(u,v)) return u;
    for(ll i=17;i>=0;i--)
     if(!line(up[v][i],u))
      v = up[v][i];
    return up[v][0];
}

int main(void) {
    #ifndef ONLINE_JUDGE
        freopen("input.txt","rt",stdin);
        freopen("output.txt","wt",stdout);
    #endif
    ll n; cin >> n;
    g.resize(n+1);
    for(ll i=0;i<n-1;i++) {
        ll x, y; cin >> x >> y;
        g[x].pb(mp(y,i)); g[y].pb(mp(x,i));
    }
    dfs(1);
    ll m; cin >> m;
    for(ll i=0;i<m;i++) {
        ll x, y; cin >> x >> y;
        add[x]++; add[y]++;
        ll z = lca(x,y);
        if(z == x || z == y) add[z]--; else
        add[z] -= 2;
    }
    get(1,0);
    for(ll i=0;i<n-1;i++)
     cout << ans[i] << " ";
    cout << endl;
    return 0;
}


#pragma comment(linker,"/STACK:100000000,100000000")

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <string>
#include <cstring>
#include <vector>
#include <stack>
#include <cmath>
#include <map>
#include <stack>
#include <set>
#include <iomanip>
#include <queue>
#include <map>
#include <functional>
#include <memory.h>
#include <list>
#include <sstream>
#include <ctime>
#include <climits>
#include <bitset>

using namespace std;

/* Constants begin */
const long long inf = 1e18+7;
const long long mod = 1e9+7;
const double eps = 1e-9;
const double PI = 2*acos(0.0);
const double E = 2.71828;
/* Constants end */

/* Defines begin */
#define pb push_back
#define mp make_pair
#define ll long long
#define double long double
#define F first
#define S second
#define all(a) (a).begin(), (a).end()
#define forn(i,n) for (ll (i)=0;(i)<(ll)(n);(i)++)
/* Defines end */

vector< vector< pair<ll,ll> > > g;
ll up[100005][18];
ll tin[100005], tout[100005], timer = 0;
ll ans[100005];
multiset<ll> S;
vector<ll> add[100005], del[100005];

void get(ll v, ll p = -1) {
    for(ll i=0;i<add[v].size();i++)
     S.insert(add[v][i]);
    for(ll i=0;i<del[v].size();i++)
     S.erase(S.find(del[v][i]));
    for(ll i=0;i<g[v].size();i++) {
        ll to = g[v][i].F;
        if(to != p) {
            ll num = S.size();
            get(to,v);
            ans[g[v][i].S] += num-S.size();
        }
    }
}

void dfs(ll v, ll p = 1) {
    tin[v] = timer++;
    up[v][0] = p;
    for(ll i=1;i<=17;i++)
     up[v][i] = up[up[v][i-1]][i-1];
    for(ll i=0;i<g[v].size();i++) {
        ll to = g[v][i].F;
        if(p != to) dfs(to,v);
    }
    tout[v] = timer++;
}

ll line(ll v, ll u) {
    return tout[v] >= tout[u] && tin[v] <= tin[u];
}

ll lca(ll v, ll u) {
    if(line(v,u)) return v;
    if(line(u,v)) return u;
    for(ll i=17;i>=0;i--)
     if(!line(up[v][i],u))
      v = up[v][i];
    return up[v][0];
}

int main(void) {
    #ifndef ONLINE_JUDGE
        freopen("input.txt","rt",stdin);
        freopen("output.txt","wt",stdout);
    #endif
    ll n; cin >> n;
    g.resize(n+1);
    for(ll i=0;i<n-1;i++) {
        ll x, y; cin >> x >> y;
        g[x].pb(mp(y,i)); g[y].pb(mp(x,i));
    }
    dfs(1);
    ll m; cin >> m;
    for(ll i=0;i<m;i++) {
        ll x, y; cin >> x >> y;
        ll z = lca(x,y);
        add[z].pb(x); add[z].pb(y);
        del[x].pb(x); del[y].pb(y);
    }
    get(1);
    for(ll i=0;i<n-1;i++)
     cout << ans[i] << " ";
    cout << endl;
    return 0;
}


#include <iostream>
#include <cstdio>
#include <vector>
#include <cmath>
#include <algorithm>
#include <string>
#include <queue>
#include <utility>
#include <set>
#include <iomanip>
#include <ctime>

using namespace std;

#define ll long long
#define pi 3.141592653589793
#define pb push_back
#define forto(l,a,b) for(long long l = a; l <= b; ++l)
#define downto(l,a,b) for(long long l = a; l >= b; --l)
#define Fred_Flinstone ios_base::sync_with_stdio(0); cin.tie(0); cout.tie(0)
#define ln '\n'
#define decimal cout<<fixed<<setprecision(15)

vector< pair< long, long > > v[100001];
vector< long > euler; //euler size is 2*n -1; fi - vert; se - entrance road;
vector< long > first(100001, -1), dis(100001, -1);
bool vis[100001] = {};
long ans[100000] = {}, cur[100001] = {}, st[200000][18], n, maxdist = -1;

bool cmp(long &a, long &b){
    return dis[a] < dis[b];
}

void dfs(long n, long d){
    euler.pb(n);
    dis[n] = d;
    maxdist = max(maxdist, d);
    if (first[n] == -1){
        first[n] = euler.size()-1;
    }
    if (v[n].size()){//always true for tree, duh...
        forto(f, 0, v[n].size()-1){
            if (dis[v[n][f].first] == -1){
                dfs(v[n][f].first, d+1);
                euler.pb(n);
            }
        }
    }
}

void buildsparse(){
    long r = 2*n-2;

    forto(f, 0, r){
        st[f][0] = euler[f];
    }

    for(long j=1; 1 << j <= r+1; j ++){
        for(long i=0; i + (1 << j) <= r; i++){
            if( dis[ st[i][j-1] ] < dis[ st[i + (1 << (j-1))][j-1] ] ){
                st[i][j] = st[i][j-1];
            }
            else{
                st[i][j] = st[i + (1 << (j-1))][j-1];
            }
        }
    }
}

long lca(long a, long b){
    if (first[a] > first[b]) swap(a, b);
    long l = first[a], r = first[b], k = trunc(log2(r-l+1));
    if ( dis[ st[l][k] ] < dis[ st[r - (1 << k) +1][k] ] ) return st[l][k];
    else return st[r - (1 << k) +1][k];
}

void solve(){
    vector< long > que;
    forto(f, 1, n){
        que.pb(f);
    }
    sort(que.begin(), que.end(), cmp);

    while (!que.empty()){
        long now = que[que.size() -1];
        que.pop_back();
        vis[now] = 1;
        forto(f, 0, v[now].size() -1){
            if (!vis[ v[now][f].first ]){
                ans[ v[now][f].second ] += cur[now];
                cur[v[now][f].first] += cur[now];
            }
        }
    }

}

int main()
{
    Fred_Flinstone;
    long k;

    cin >> n;
    forto(f, 1, n-1){
        long x, y;
        cin >> x >> y;
        v[x].pb(make_pair(y, f));
        v[y].pb(make_pair(x, f));
    }

    dfs(1, 0);
    buildsparse();

    cin >> k;
    forto(f, 1, k){
        long x, y, z;
        cin >> x >> y;
        z = lca(x, y);
        cur[z] -= 2;
        cur[x] ++;
        cur[y] ++;
    }

    solve();

    forto(f, 1, n-1){
        cout << ans[f] << ' ';
    }

    return 0;
}


#include <iostream>
#include <cstring>

#include <vector>
#include <string>
#include <stack>
#include <algorithm>

using namespace std;

typedef vector<int> VI;
typedef vector<VI> VVI;
typedef pair<int,int> II;
typedef long long llong;

#define HIGHESTSETBIT(mask) ( sizeof(int)*8-1-__builtin_clz((mask)) )

struct SegmentTreeNode {
   llong sum;
   bool delay;
   SegmentTreeNode() : sum(0), delay(0) {}
};

class SegmentTree {
   int N;

   void _update(int p, int q, int node, int L, int R);
   int  _count (int p, int q, int node, int L, int R);
public:
   vector<SegmentTreeNode> tree;
   SegmentTree(int _N) : N(_N) {
   // int M = 2 * ( 1 << (HIGHESTSETBIT(N)+1) ) + 1;
      int M = N > 1 ? 2 * ( 1 << (HIGHESTSETBIT(N-1)+1) ) : 2;
      tree = vector<SegmentTreeNode>(M);
   }
   void update(int p, int q) {
      _update(p, q, 1, 0, N-1);
   }
   int count(int p, int q) {
      return _count(p, q, 1, 0, N-1);
   }
};

void SegmentTree::_update(int p, int q, int node, int L, int R) {
   if (q < L || p > R) return;
   if (p <= L && R <= q) {
      tree[node].sum += R-L+1;
      tree[node].delay = true;
      return;
   }
   tree[node].delay = false;
   int cL = node*2;
   int cR = node*2 + 1;
   _update(p, q, cL, L, (L+R)/2);
   _update(p, q, cR, (L+R)/2+1, R);
   tree[node].sum = tree[cL].sum + tree[cR].sum;
}

int SegmentTree::_count(int p, int q, int node, int L, int R) {
   if (q < L || p > R) return 0;
   if (p <= L && R <= q)
      return tree[node].sum;
   int cL = node*2;
   int cR = node*2 + 1;
   if (tree[node].delay) {
   // cerr << node << ' ' << p << ' ' << q << "  OK" << endl;
      tree[node].delay = false;
      tree[node].sum -= R-L+1;
      tree[cL].sum += (L+R)/2 - L + 1;
      tree[cR].sum += R - ((L+R)/2+1) + 1;
   }
   return _count(p, q, cL, L, (L+R)/2) +
          _count(p, q, cR, (L+R)/2+1, R);
}

vector<SegmentTree> segm_trees;

class TreeDecomposition {
   int root;
   VI vis;
   VI par;
   VI Td, Tf;  // discovery and finish times in DFS
   VI subtree_size;

   vector<int> prefix_walk;
   void _dfs();

public:
// INPUT:
   VVI adj;

// OUTPUT:
   VVI chains;
   vector<II> node_chain_pos;
   // node_chain_pos[v] = (chain id, offset in path) of node v

   TreeDecomposition(int _N) : adj(_N) {}

   void decompose();

// return whether u is an ancestor of v
   bool is_ancestor(int u, int v) const;
};

void TreeDecomposition::_dfs() {
   int N = adj.size();
   vis = VI(N);
   par = VI(N, -1);
   Td = VI(N);
   Tf = VI(N);

   subtree_size = VI(N);
   root = 0;
   stack<II> S;
   S.push(II(root, 0));
   par[root] = root;
   for (int t = 1; !S.empty(); ++t) {
      int u = S.top().first, e = S.top().second;
      if (e == 0) {
         vis[u] = 2;
         Td[u] = t;
      }
      if (e == int(adj[u].size())) {
         Tf[u] = t;
         subtree_size[u] = 1;
         for (int j = 0; j < int(adj[u].size()); ++j) {
            int v = adj[u][j];
            if (v == par[u]) continue;
            subtree_size[u] += subtree_size[v];
         }
         prefix_walk.push_back(u);
         S.pop();
      }
      else {
         ++S.top().second;
         int v = adj[u][e];
         if (!vis[v]) {
            vis[v] = 1;
            par[v] = u;
            S.push(II(v, 0));
         }
      }
   }
}

void TreeDecomposition::decompose() {
   _dfs();

   int N = adj.size();
   vector<bool> par_edge_processed(N);
   par_edge_processed[root] = true;
   for (int k = 0; k < (int) prefix_walk.size(); ++k) {
      int v = prefix_walk[k];
      if (par_edge_processed[v]) continue;
      vector<int> cur_path;
      cur_path.push_back(v);
      do {
         int u = par[v];
         cur_path.push_back(u);
         par_edge_processed[v] = true;
         if (2*subtree_size[v] < subtree_size[u]) break;  // light edge
         v = u;
      } while (!par_edge_processed[v]);
      chains.push_back(cur_path);
   }

   node_chain_pos = vector<II>(N);
   node_chain_pos[0].first = -1;
   for (int i = 0; i < (int) chains.size(); ++i) {
   // fprintf(stderr, "path %d:", i);
      for (int j = 0; j < int(chains[i].size())-1; ++j) {
         int u = chains[i][j];
      // fprintf(stderr, " %d", u);
         node_chain_pos[u] = II(i, j);
      }
   // fprintf(stderr, " %d\n", chains[i].back());
   }
}

inline bool TreeDecomposition::is_ancestor(int u, int v) const {
   return Td[u] <= Td[v] && Tf[v] <= Tf[u];
}

void update(const TreeDecomposition& td, int u, int v) {
   while (u != v) {
      if (td.is_ancestor(u, v))
         swap(u, v);
      int p = td.node_chain_pos[u].first;
      int lo = td.node_chain_pos[u].second,
          hi = int(td.chains[p].size())-1;
      if (td.is_ancestor(td.chains[p][hi], v)) {
         // binary search for lowest common ancestor
         while (lo < hi) {
            int mid = lo + (hi-lo)/2;
            if (td.is_ancestor(td.chains[p][mid], v))
               hi = mid;
            else
               lo = mid+1;
         }
         hi = lo;
         lo = td.node_chain_pos[u].second; // restore lo
      }
      segm_trees[p].update(lo, hi-1);
      u = td.chains[p][hi];
   }
}

llong query(const TreeDecomposition& td, int u, int v) {
   llong res = 0;
   while (u != v) {
      if (td.is_ancestor(u, v))
         swap(u, v);
      int p = td.node_chain_pos[u].first;
      int lo = td.node_chain_pos[u].second,
          hi = int(td.chains[p].size())-1;
      if (td.is_ancestor(td.chains[p][hi], v)) {
         // binary search for lowest common ancestor
         while (lo < hi) {
            int mid = lo + (hi-lo)/2;
            if (td.is_ancestor(td.chains[p][mid], v))
               hi = mid;
            else
               lo = mid+1;
         }
         hi = lo;
         lo = td.node_chain_pos[u].second; // restore lo
      }
      res += segm_trees[p].count(lo, hi-1);
      u = td.chains[p][hi];
   }
   return res;
}

struct Road {
   int u, v;
};

Road roads[100004];

int main(int argc, char* argv[]) {
   cin.sync_with_stdio(false);
   int N;
   cin >> N;
   TreeDecomposition td(N);
   for (int j = 1; j < N; ++j) {
      int u, v;
      cin >> u >> v;
      --u, --v;
      roads[j].u = u;
      roads[j].v = v;
      td.adj[u].push_back(v);
      td.adj[v].push_back(u);
   }

   td.decompose();

   segm_trees.clear();
   for (int i = 0; i < int(td.chains.size()); ++i)
      segm_trees.push_back(
         SegmentTree( int(td.chains[i].size())-1 ) );

   int Q;
   cin >> Q;
   for (int q = 1; q <= Q; ++q) {
      int u, v;
      cin >> u >> v;
      if (u == v) continue;
      --u, --v;
      update(td, u, v);
   }

   for (int j = 1; j < N; ++j) {
      llong res = query(td, roads[j].u, roads[j].v);
      if (j > 1) cout << ' ';
      cout << res;
   }
   cout << endl;

   return 0;
}


#include <iostream>
#include <cstring>

#include <vector>
#include <string>
#include <stack>
#include <algorithm>

using namespace std;

typedef vector<int> VI;
typedef vector<VI> VVI;
typedef pair<int,int> II;
typedef long long llong;

#define HIGHESTSETBIT(mask) ( sizeof(int)*8-1-__builtin_clz((mask)) )

struct SegmentTreeNode {
   llong sum;
   bool delay;
   SegmentTreeNode() : sum(0), delay(0) {}
};

class SegmentTree {
   int N;

   void _update(int p, int q, int node, int L, int R);
   int  _count (int p, int q, int node, int L, int R);
public:
   vector<SegmentTreeNode> tree;
   SegmentTree(int _N) : N(_N) {
   // int M = 2 * ( 1 << (HIGHESTSETBIT(N)+1) ) + 1;
      int M = N > 1 ? 2 * ( 1 << (HIGHESTSETBIT(N-1)+1) ) : 2;
      tree = vector<SegmentTreeNode>(M);
   }
   void update(int p, int q) {
      _update(p, q, 1, 0, N-1);
   }
   int count(int p, int q) {
      return _count(p, q, 1, 0, N-1);
   }
};

void SegmentTree::_update(int p, int q, int node, int L, int R) {
   if (q < L || p > R) return;
   if (p <= L && R <= q) {
      tree[node].sum += R-L+1;
      tree[node].delay = true;
      return;
   }
   int cL = node*2;
   int cR = node*2 + 1;
   if (tree[node].delay) {
      tree[node].delay = false;
      tree[node].sum -= R-L+1;
      tree[cL].delay = true;
      tree[cL].sum += (L+R)/2 - L + 1;
      tree[cR].delay = true;
      tree[cR].sum += R - ((L+R)/2+1) + 1;
   }
   _update(p, q, cL, L, (L+R)/2);
   _update(p, q, cR, (L+R)/2+1, R);
   tree[node].sum = tree[cL].sum + tree[cR].sum;
}

int SegmentTree::_count(int p, int q, int node, int L, int R) {
   if (q < L || p > R) return 0;
   if (p <= L && R <= q)
      return tree[node].sum;
   int cL = node*2;
   int cR = node*2 + 1;
   if (tree[node].delay) {
   // cerr << node << ' ' << p << ' ' << q << "  OK" << endl;
      tree[node].delay = false;
      tree[node].sum -= R-L+1;
      tree[cL].delay = true;
      tree[cL].sum += (L+R)/2 - L + 1;
      tree[cR].delay = true;
      tree[cR].sum += R - ((L+R)/2+1) + 1;
   }
   return _count(p, q, cL, L, (L+R)/2) +
          _count(p, q, cR, (L+R)/2+1, R);
}

vector<SegmentTree> segm_trees;

class TreeDecomposition {
   int root;
   VI vis;
   VI par;
   VI Td, Tf;  // discovery and finish times in DFS
   VI subtree_size;

   vector<int> prefix_walk;
   void _dfs();

public:
// INPUT:
   VVI adj;

// OUTPUT:
   VVI chains;
   vector<II> node_chain_pos;
   // node_chain_pos[v] = (chain id, offset in path) of node v

   TreeDecomposition(int _N) : adj(_N) {}

   void decompose();

// return whether u is an ancestor of v
   bool is_ancestor(int u, int v) const;
};

void TreeDecomposition::_dfs() {
   int N = adj.size();
   vis = VI(N);
   par = VI(N, -1);
   Td = VI(N);
   Tf = VI(N);

   subtree_size = VI(N);
   root = 0;
   stack<II> S;
   S.push(II(root, 0));
   par[root] = root;
   for (int t = 1; !S.empty(); ++t) {
      int u = S.top().first, e = S.top().second;
      if (e == 0) {
         vis[u] = 2;
         Td[u] = t;
      }
      if (e == int(adj[u].size())) {
         Tf[u] = t;
         subtree_size[u] = 1;
         for (int j = 0; j < int(adj[u].size()); ++j) {
            int v = adj[u][j];
            if (v == par[u]) continue;
            subtree_size[u] += subtree_size[v];
         }
         prefix_walk.push_back(u);
         S.pop();
      }
      else {
         ++S.top().second;
         int v = adj[u][e];
         if (!vis[v]) {
            vis[v] = 1;
            par[v] = u;
            S.push(II(v, 0));
         }
      }
   }
}

void TreeDecomposition::decompose() {
   _dfs();

   int N = adj.size();
   vector<bool> par_edge_processed(N);
   par_edge_processed[root] = true;
   for (int k = 0; k < (int) prefix_walk.size(); ++k) {
      int v = prefix_walk[k];
      if (par_edge_processed[v]) continue;
      vector<int> cur_path;
      cur_path.push_back(v);
      do {
         int u = par[v];
         cur_path.push_back(u);
         par_edge_processed[v] = true;
         if (2*subtree_size[v] < subtree_size[u]) break;  // light edge
         v = u;
      } while (!par_edge_processed[v]);
      chains.push_back(cur_path);
   }

   node_chain_pos = vector<II>(N);
   node_chain_pos[0].first = -1;
   for (int i = 0; i < (int) chains.size(); ++i) {
   // fprintf(stderr, "path %d:", i);
      for (int j = 0; j < int(chains[i].size())-1; ++j) {
         int u = chains[i][j];
      // fprintf(stderr, " %d", u);
         node_chain_pos[u] = II(i, j);
      }
   // fprintf(stderr, " %d\n", chains[i].back());
   }
}

inline bool TreeDecomposition::is_ancestor(int u, int v) const {
   return Td[u] <= Td[v] && Tf[v] <= Tf[u];
}

void update(const TreeDecomposition& td, int u, int v) {
   while (u != v) {
      if (td.is_ancestor(u, v))
         swap(u, v);
      int p = td.node_chain_pos[u].first;
      int lo = td.node_chain_pos[u].second,
          hi = int(td.chains[p].size())-1;
      if (td.is_ancestor(td.chains[p][hi], v)) {
         // binary search for lowest common ancestor
         while (lo < hi) {
            int mid = lo + (hi-lo)/2;
            if (td.is_ancestor(td.chains[p][mid], v))
               hi = mid;
            else
               lo = mid+1;
         }
         hi = lo;
         lo = td.node_chain_pos[u].second; // restore lo
      }
      segm_trees[p].update(lo, hi-1);
      u = td.chains[p][hi];
   }
}

llong query(const TreeDecomposition& td, int u, int v) {
   llong res = 0;
   while (u != v) {
      if (td.is_ancestor(u, v))
         swap(u, v);
      int p = td.node_chain_pos[u].first;
      int lo = td.node_chain_pos[u].second,
          hi = int(td.chains[p].size())-1;
      if (td.is_ancestor(td.chains[p][hi], v)) {
         // binary search for lowest common ancestor
         while (lo < hi) {
            int mid = lo + (hi-lo)/2;
            if (td.is_ancestor(td.chains[p][mid], v))
               hi = mid;
            else
               lo = mid+1;
         }
         hi = lo;
         lo = td.node_chain_pos[u].second; // restore lo
      }
      res += segm_trees[p].count(lo, hi-1);
      u = td.chains[p][hi];
   }
   return res;
}

struct Road {
   int u, v;
};

Road roads[100004];

int main(int argc, char* argv[]) {
   cin.sync_with_stdio(false);
   int N;
   cin >> N;
   TreeDecomposition td(N);
   for (int j = 1; j < N; ++j) {
      int u, v;
      cin >> u >> v;
      --u, --v;
      roads[j].u = u;
      roads[j].v = v;
      td.adj[u].push_back(v);
      td.adj[v].push_back(u);
   }

   td.decompose();

   segm_trees.clear();
   for (int i = 0; i < int(td.chains.size()); ++i)
      segm_trees.push_back(
         SegmentTree( int(td.chains[i].size())-1 ) );

   int Q;
   cin >> Q;
   for (int q = 1; q <= Q; ++q) {
      int u, v;
      cin >> u >> v;
      if (u == v) continue;
      --u, --v;
      update(td, u, v);
   }

   for (int j = 1; j < N; ++j) {
      llong res = query(td, roads[j].u, roads[j].v);
      if (j > 1) cout << ' ';
      cout << res;
   }
   cout << endl;

   return 0;
}


#include <iostream>
#include <cstring>

#include <vector>
#include <string>
#include <stack>
#include <algorithm>

using namespace std;

typedef vector<int> VI;
typedef vector<VI> VVI;
typedef pair<int,int> II;
typedef long long llong;

#define HIGHESTSETBIT(mask) ( sizeof(int)*8-1-__builtin_clz((mask)) )

struct SegmentTreeNode {
   llong sum;
   bool delay;
   SegmentTreeNode() : sum(0), delay(0) {}
};

class SegmentTree {
   int N;

   void _update(int p, int q, int node, int L, int R);
   int  _count (int p, int q, int node, int L, int R);
public:
   vector<SegmentTreeNode> tree;
   SegmentTree(int _N) : N(_N) {
   // int M = 2 * ( 1 << (HIGHESTSETBIT(N)+1) ) + 1;
      int M = N > 1 ? 2 * ( 1 << (HIGHESTSETBIT(N-1)+1) ) : 2;
      tree = vector<SegmentTreeNode>(M);
   }
   void update(int p, int q) {
      _update(p, q, 1, 0, N-1);
   }
   int count(int p, int q) {
      return _count(p, q, 1, 0, N-1);
   }
};

void SegmentTree::_update(int p, int q, int node, int L, int R) {
   if (q < L || p > R) return;
   if (p <= L && R <= q) {
      tree[node].sum += R-L+1;
      tree[node].delay = true;
      return;
   }
   int cL = node*2;
   int cR = node*2 + 1;
   if (tree[node].delay) {
      tree[node].delay = false;
      tree[node].sum -= R-L+1;
      tree[cL].sum += (L+R)/2 - L + 1;
      tree[cR].sum += R - ((L+R)/2+1) + 1;
   }
   _update(p, q, cL, L, (L+R)/2);
   _update(p, q, cR, (L+R)/2+1, R);
   tree[node].sum = tree[cL].sum + tree[cR].sum;
}

int SegmentTree::_count(int p, int q, int node, int L, int R) {
   if (q < L || p > R) return 0;
   if (p <= L && R <= q)
      return tree[node].sum;
   int cL = node*2;
   int cR = node*2 + 1;
   if (tree[node].delay) {
   // cerr << node << ' ' << p << ' ' << q << "  OK" << endl;
      tree[node].delay = false;
      tree[node].sum -= R-L+1;
      tree[cL].sum += (L+R)/2 - L + 1;
      tree[cR].sum += R - ((L+R)/2+1) + 1;
   }
   return _count(p, q, cL, L, (L+R)/2) +
          _count(p, q, cR, (L+R)/2+1, R);
}

vector<SegmentTree> segm_trees;

class TreeDecomposition {
   int root;
   VI vis;
   VI par;
   VI Td, Tf;  // discovery and finish times in DFS
   VI subtree_size;

   vector<int> prefix_walk;
   void _dfs();

public:
// INPUT:
   VVI adj;

// OUTPUT:
   VVI chains;
   vector<II> node_chain_pos;
   // node_chain_pos[v] = (chain id, offset in path) of node v

   TreeDecomposition(int _N) : adj(_N) {}

   void decompose();

// return whether u is an ancestor of v
   bool is_ancestor(int u, int v) const;
};

void TreeDecomposition::_dfs() {
   int N = adj.size();
   vis = VI(N);
   par = VI(N, -1);
   Td = VI(N);
   Tf = VI(N);

   subtree_size = VI(N);
   root = 0;
   stack<II> S;
   S.push(II(root, 0));
   par[root] = root;
   for (int t = 1; !S.empty(); ++t) {
      int u = S.top().first, e = S.top().second;
      if (e == 0) {
         vis[u] = 2;
         Td[u] = t;
      }
      if (e == int(adj[u].size())) {
         Tf[u] = t;
         subtree_size[u] = 1;
         for (int j = 0; j < int(adj[u].size()); ++j) {
            int v = adj[u][j];
            if (v == par[u]) continue;
            subtree_size[u] += subtree_size[v];
         }
         prefix_walk.push_back(u);
         S.pop();
      }
      else {
         ++S.top().second;
         int v = adj[u][e];
         if (!vis[v]) {
            vis[v] = 1;
            par[v] = u;
            S.push(II(v, 0));
         }
      }
   }
}

void TreeDecomposition::decompose() {
   _dfs();

   int N = adj.size();
   vector<bool> par_edge_processed(N);
   par_edge_processed[root] = true;
   for (int k = 0; k < (int) prefix_walk.size(); ++k) {
      int v = prefix_walk[k];
      if (par_edge_processed[v]) continue;
      vector<int> cur_path;
      cur_path.push_back(v);
      do {
         int u = par[v];
         cur_path.push_back(u);
         par_edge_processed[v] = true;
         if (2*subtree_size[v] < subtree_size[u]) break;  // light edge
         v = u;
      } while (!par_edge_processed[v]);
      chains.push_back(cur_path);
   }

   node_chain_pos = vector<II>(N);
   node_chain_pos[0].first = -1;
   for (int i = 0; i < (int) chains.size(); ++i) {
   // fprintf(stderr, "path %d:", i);
      for (int j = 0; j < int(chains[i].size())-1; ++j) {
         int u = chains[i][j];
      // fprintf(stderr, " %d", u);
         node_chain_pos[u] = II(i, j);
      }
   // fprintf(stderr, " %d\n", chains[i].back());
   }
}

inline bool TreeDecomposition::is_ancestor(int u, int v) const {
   return Td[u] <= Td[v] && Tf[v] <= Tf[u];
}

void update(const TreeDecomposition& td, int u, int v) {
   while (u != v) {
      if (td.is_ancestor(u, v))
         swap(u, v);
      int p = td.node_chain_pos[u].first;
      int lo = td.node_chain_pos[u].second,
          hi = int(td.chains[p].size())-1;
      if (td.is_ancestor(td.chains[p][hi], v)) {
         // binary search for lowest common ancestor
         while (lo < hi) {
            int mid = lo + (hi-lo)/2;
            if (td.is_ancestor(td.chains[p][mid], v))
               hi = mid;
            else
               lo = mid+1;
         }
         hi = lo;
         lo = td.node_chain_pos[u].second; // restore lo
      }
      segm_trees[p].update(lo, hi-1);
      u = td.chains[p][hi];
   }
}

llong query(const TreeDecomposition& td, int u, int v) {
   llong res = 0;
   while (u != v) {
      if (td.is_ancestor(u, v))
         swap(u, v);
      int p = td.node_chain_pos[u].first;
      int lo = td.node_chain_pos[u].second,
          hi = int(td.chains[p].size())-1;
      if (td.is_ancestor(td.chains[p][hi], v)) {
         // binary search for lowest common ancestor
         while (lo < hi) {
            int mid = lo + (hi-lo)/2;
            if (td.is_ancestor(td.chains[p][mid], v))
               hi = mid;
            else
               lo = mid+1;
         }
         hi = lo;
         lo = td.node_chain_pos[u].second; // restore lo
      }
      res += segm_trees[p].count(lo, hi-1);
      u = td.chains[p][hi];
   }
   return res;
}

struct Road {
   int u, v;
};

Road roads[100004];

int main(int argc, char* argv[]) {
   cin.sync_with_stdio(false);
   int N;
   cin >> N;
   TreeDecomposition td(N);
   for (int j = 1; j < N; ++j) {
      int u, v;
      cin >> u >> v;
      --u, --v;
      roads[j].u = u;
      roads[j].v = v;
      td.adj[u].push_back(v);
      td.adj[v].push_back(u);
   }

   td.decompose();

   segm_trees.clear();
   for (int i = 0; i < int(td.chains.size()); ++i)
      segm_trees.push_back(
         SegmentTree( int(td.chains[i].size())-1 ) );

   int Q;
   cin >> Q;
   for (int q = 1; q <= Q; ++q) {
      int u, v;
      cin >> u >> v;
      if (u == v) continue;
      --u, --v;
      update(td, u, v);
   }

   for (int j = 1; j < N; ++j) {
      llong res = query(td, roads[j].u, roads[j].v);
      if (j > 1) cout << ' ';
      cout << res;
   }
   cout << endl;

   return 0;
}


#include <iostream>
#include <cstring>

#include <vector>
#include <string>
#include <stack>
#include <algorithm>

using namespace std;

typedef vector<int> VI;
typedef vector<VI> VVI;
typedef pair<int,int> II;
typedef long long llong;

#define HIGHESTSETBIT(mask) ( sizeof(int)*8-1-__builtin_clz((mask)) )

bool trace;

struct SegmentTreeNode {
   llong sum;
   llong delay_count;
   SegmentTreeNode() : sum(0), delay_count(0) {}
};

class SegmentTree {
   int N;

   void _update(int p, int q, int node, int L, int R);
   int  _count (int p, int q, int node, int L, int R);
public:
   vector<SegmentTreeNode> tree;
   SegmentTree(int _N) : N(_N) {
   // int M = 2 * ( 1 << (HIGHESTSETBIT(N)+1) ) + 1;
      int M = N > 1 ? 2 * ( 1 << (HIGHESTSETBIT(N-1)+1) ) : 2;
      tree = vector<SegmentTreeNode>(M);
   }
   void update(int p, int q) {
      _update(p, q, 1, 0, N-1);
   }
   int count(int p, int q) {
      return _count(p, q, 1, 0, N-1);
   }
};

void SegmentTree::_update(int p, int q, int node, int L, int R) {
   if (q < L || p > R) return;
   if (p <= L && R <= q) {
      tree[node].sum += R-L+1;
      tree[node].delay_count++;
      return;
   }
   int cL = node*2;
   int cR = node*2 + 1;
   if (tree[node].delay_count > 0) {
      tree[cL].delay_count += tree[node].delay_count;
      tree[cL].sum += ((L+R)/2 - L + 1) * tree[node].delay_count;
      tree[cR].delay_count += tree[node].delay_count;
      tree[cR].sum += (R - ((L+R)/2+1) + 1) * tree[node].delay_count;
      tree[node].delay_count = 0;
   // tree[node].sum -= R-L+1;
   }
   _update(p, q, cL, L, (L+R)/2);
   _update(p, q, cR, (L+R)/2+1, R);
   tree[node].sum = tree[cL].sum + tree[cR].sum;
}

int SegmentTree::_count(int p, int q, int node, int L, int R) {
   if (q < L || p > R) return 0;
   if (p <= L && R <= q)
      return tree[node].sum;
   int cL = node*2;
   int cR = node*2 + 1;
   if (tree[node].delay_count > 0) {
      tree[cL].delay_count += tree[node].delay_count;
      tree[cL].sum += ((L+R)/2 - L + 1) * tree[node].delay_count;
      tree[cR].delay_count += tree[node].delay_count;
      tree[cR].sum += (R - ((L+R)/2+1) + 1) * tree[node].delay_count;
      tree[node].delay_count = 0;
   // tree[node].sum -= R-L+1;
   }
   return _count(p, q, cL, L, (L+R)/2) +
          _count(p, q, cR, (L+R)/2+1, R);
}

vector<SegmentTree> segm_trees;

class TreeDecomposition {
   int root;
   VI vis;
   VI par;
   VI Td, Tf;  // discovery and finish times in DFS
   VI subtree_size;

   vector<int> prefix_walk;
   void _dfs();

public:
// INPUT:
   VVI adj;

// OUTPUT:
   VVI chains;
   vector<II> node_chain_pos;
   // node_chain_pos[v] = (chain id, offset in path) of node v

   TreeDecomposition(int _N) : adj(_N) {}

   void decompose();

// return whether u is an ancestor of v
   bool is_ancestor(int u, int v) const;
};

void TreeDecomposition::_dfs() {
   int N = adj.size();
   vis = VI(N);
   par = VI(N, -1);
   Td = VI(N);
   Tf = VI(N);

   subtree_size = VI(N);
   root = 0;
   stack<II> S;
   S.push(II(root, 0));
   par[root] = root;
   for (int t = 1; !S.empty(); ++t) {
      int u = S.top().first, e = S.top().second;
      if (e == 0) {
         vis[u] = 2;
         Td[u] = t;
      }
      if (e == int(adj[u].size())) {
         Tf[u] = t;
         subtree_size[u] = 1;
         for (int j = 0; j < int(adj[u].size()); ++j) {
            int v = adj[u][j];
            if (v == par[u]) continue;
            subtree_size[u] += subtree_size[v];
         }
         prefix_walk.push_back(u);
         S.pop();
      }
      else {
         ++S.top().second;
         int v = adj[u][e];
         if (!vis[v]) {
            vis[v] = 1;
            par[v] = u;
            S.push(II(v, 0));
         }
      }
   }
}

void TreeDecomposition::decompose() {
   _dfs();

   int N = adj.size();
   vector<bool> par_edge_processed(N);
   par_edge_processed[root] = true;
   for (int k = 0; k < (int) prefix_walk.size(); ++k) {
      int v = prefix_walk[k];
      if (par_edge_processed[v]) continue;
      vector<int> cur_path;
      cur_path.push_back(v);
      do {
         int u = par[v];
         cur_path.push_back(u);
         par_edge_processed[v] = true;
         if (2*subtree_size[v] < subtree_size[u]) break;  // light edge
         v = u;
      } while (!par_edge_processed[v]);
      chains.push_back(cur_path);
   }

   node_chain_pos = vector<II>(N);
   node_chain_pos[0].first = -1;
   for (int i = 0; i < (int) chains.size(); ++i) {
   // cerr << "path " << i << ": ";
      for (int j = 0; j < int(chains[i].size())-1; ++j) {
         int u = chains[i][j];
      // cerr << ' ' << u+1;
         node_chain_pos[u] = II(i, j);
      }
   // cerr << ' ' << chains[i].back()+1 << endl;
   }
}

inline bool TreeDecomposition::is_ancestor(int u, int v) const {
   return Td[u] <= Td[v] && Tf[v] <= Tf[u];
}

void update(const TreeDecomposition& td, int u, int v) {
   while (u != v) {
      if (td.is_ancestor(u, v))
         swap(u, v);
      int p = td.node_chain_pos[u].first;
      int lo = td.node_chain_pos[u].second,
          hi = int(td.chains[p].size())-1;
      if (td.is_ancestor(td.chains[p][hi], v)) {
         // binary search for lowest common ancestor
         while (lo < hi) {
            int mid = lo + (hi-lo)/2;
            if (td.is_ancestor(td.chains[p][mid], v))
               hi = mid;
            else
               lo = mid+1;
         }
         hi = lo;
         lo = td.node_chain_pos[u].second; // restore lo
      }
   // trace = p == 2;
   // cerr << "Update segment tree " << p << ": " << lo << " " << hi-1 << endl;
      segm_trees[p].update(lo, hi-1);
      u = td.chains[p][hi];
   }
}

llong query(const TreeDecomposition& td, int u, int v) {
   llong res = 0;
   while (u != v) {
      if (td.is_ancestor(u, v))
         swap(u, v);
      int p = td.node_chain_pos[u].first;
      int lo = td.node_chain_pos[u].second,
          hi = int(td.chains[p].size())-1;
      if (td.is_ancestor(td.chains[p][hi], v)) {
         // binary search for lowest common ancestor
         while (lo < hi) {
            int mid = lo + (hi-lo)/2;
            if (td.is_ancestor(td.chains[p][mid], v))
               hi = mid;
            else
               lo = mid+1;
         }
         hi = lo;
         lo = td.node_chain_pos[u].second; // restore lo
      }
      res += segm_trees[p].count(lo, hi-1);
      u = td.chains[p][hi];
   }
   return res;
}

struct Road {
   int u, v;
};

Road roads[100004];

int main(int argc, char* argv[]) {
   cin.sync_with_stdio(false);
   int N;
   cin >> N;
   TreeDecomposition td(N);
   for (int j = 1; j < N; ++j) {
      int u, v;
      cin >> u >> v;
      --u, --v;
      roads[j].u = u;
      roads[j].v = v;
      td.adj[u].push_back(v);
      td.adj[v].push_back(u);
   }

   td.decompose();

   segm_trees.clear();
   for (int i = 0; i < int(td.chains.size()); ++i)
      segm_trees.push_back(
         SegmentTree( int(td.chains[i].size())-1 ) );

   int Q;
   cin >> Q;
   for (int q = 1; q <= Q; ++q) {
      int u, v;
      cin >> u >> v;
      if (u == v) continue;
      --u, --v;
      update(td, u, v);
   }

   for (int j = 1; j < N; ++j) {
      llong res = query(td, roads[j].u, roads[j].v);
      if (j > 1) cout << ' ';
      cout << res;
   }
   cout << endl;

   return 0;
}


#include <iostream>
#include <cstring>

#include <vector>
#include <string>
#include <stack>
#include <algorithm>

using namespace std;

typedef vector<int> VI;
typedef vector<VI> VVI;
typedef pair<int,int> II;
typedef long long llong;

#define HIGHESTSETBIT(mask) ( sizeof(int)*8-1-__builtin_clz((mask)) )

struct SegmentTreeNode {
   llong sum;
   SegmentTreeNode() : sum(0) {
   }
};

class SegmentTree {
   int N;

   void _update(int p, int q, int node, int L, int R);
   int  _count (int p, int q, int node, int L, int R);
public:
   vector<SegmentTreeNode> tree;
   SegmentTree(int _N) : N(_N) {
   // int M = 2 * ( 1 << (HIGHESTSETBIT(N)+1) ) + 1;
      int M = N > 1 ? 2 * ( 1 << (HIGHESTSETBIT(N-1)+1) ) : 2;
      tree = vector<SegmentTreeNode>(M);
   }
   void update(int p, int q) {
      _update(p, q, 1, 0, N-1);
   }
   int count(int p, int q) {
      return _count(p, q, 1, 0, N-1);
   }
};

void SegmentTree::_update(int p, int q, int node, int L, int R) {
   if (q < L || p > R) return;
   if (p <= L && R <= q) {
      tree[node].sum += R-L+1;
      return;
   }
   int cL = node*2;
   int cR = node*2 + 1;
   _update(p, q, cL, L, (L+R)/2);
   _update(p, q, cR, (L+R)/2+1, R);
   tree[node].sum = tree[cL].sum + tree[cR].sum;
}

int SegmentTree::_count(int p, int q, int node, int L, int R) {
   if (q < L || p > R) return 0;
   if (p <= L && R <= q) return tree[node].sum;
   int cL = node*2;
   int cR = node*2 + 1;
   return _count(p, q, cL, L, (L+R)/2) +
          _count(p, q, cR, (L+R)/2+1, R);
}

vector<SegmentTree> segm_trees;

class TreeDecomposition {
   int root;
   VI vis;
   VI par;
   VI Td, Tf;  // discovery and finish times in DFS
   VI subtree_size;

   vector<int> prefix_walk;
   void _dfs();

public:
// INPUT:
   VVI adj;

// OUTPUT:
   VVI chains;
   vector<II> node_chain_pos;
   // node_chain_pos[v] = (chain id, offset in path) of node v

   TreeDecomposition(int _N) : adj(_N) {}

   void decompose();

// return whether u is an ancestor of v
   bool is_ancestor(int u, int v) const;
};

void TreeDecomposition::_dfs() {
   int N = adj.size();
   vis = VI(N);
   par = VI(N, -1);
   Td = VI(N);
   Tf = VI(N);

   subtree_size = VI(N);
   root = 0;
   stack<II> S;
   S.push(II(root, 0));
   par[root] = root;
   for (int t = 1; !S.empty(); ++t) {
      int u = S.top().first, e = S.top().second;
      if (e == 0) {
         vis[u] = 2;
         Td[u] = t;
      }
      if (e == int(adj[u].size())) {
         Tf[u] = t;
         subtree_size[u] = 1;
         for (int j = 0; j < int(adj[u].size()); ++j) {
            int v = adj[u][j];
            if (v == par[u]) continue;
            subtree_size[u] += subtree_size[v];
         }
         prefix_walk.push_back(u);
         S.pop();
      }
      else {
         ++S.top().second;
         int v = adj[u][e];
         if (!vis[v]) {
            vis[v] = 1;
            par[v] = u;
            S.push(II(v, 0));
         }
      }
   }
}

void TreeDecomposition::decompose() {
   _dfs();

   int N = adj.size();
   vector<bool> par_edge_processed(N);
   par_edge_processed[root] = true;
   for (int k = 0; k < (int) prefix_walk.size(); ++k) {
      int v = prefix_walk[k];
      if (par_edge_processed[v]) continue;
      vector<int> cur_path;
      cur_path.push_back(v);
      do {
         int u = par[v];
         cur_path.push_back(u);
         par_edge_processed[v] = true;
         if (2*subtree_size[v] < subtree_size[u]) break;  // light edge
         v = u;
      } while (!par_edge_processed[v]);
      chains.push_back(cur_path);
   }

   node_chain_pos = vector<II>(N);
   node_chain_pos[0].first = -1;
   for (int i = 0; i < (int) chains.size(); ++i) {
   // fprintf(stderr, "path %d:", i);
      for (int j = 0; j < int(chains[i].size())-1; ++j) {
         int u = chains[i][j];
      // fprintf(stderr, " %d", u);
         node_chain_pos[u] = II(i, j);
      }
   // fprintf(stderr, " %d\n", chains[i].back());
   }
}

inline bool TreeDecomposition::is_ancestor(int u, int v) const {
   return Td[u] <= Td[v] && Tf[v] <= Tf[u];
}

void update(const TreeDecomposition& td, int u, int v) {
   while (u != v) {
      if (td.is_ancestor(u, v))
         swap(u, v);
      int p = td.node_chain_pos[u].first;
      int lo = td.node_chain_pos[u].second,
          hi = int(td.chains[p].size())-1;
      if (td.is_ancestor(td.chains[p][hi], v)) {
         // binary search for lowest common ancestor
         while (lo < hi) {
            int mid = lo + (hi-lo)/2;
            if (td.is_ancestor(td.chains[p][mid], v))
               hi = mid;
            else
               lo = mid+1;
         }
         hi = lo;
         lo = td.node_chain_pos[u].second; // restore lo
      }
      segm_trees[p].update(lo, hi-1);
      u = td.chains[p][hi];
   }
}

llong query(const TreeDecomposition& td, int u, int v) {
   llong res = 0;
   while (u != v) {
      if (td.is_ancestor(u, v))
         swap(u, v);
      int p = td.node_chain_pos[u].first;
      int lo = td.node_chain_pos[u].second,
          hi = int(td.chains[p].size())-1;
      if (td.is_ancestor(td.chains[p][hi], v)) {
         // binary search for lowest common ancestor
         while (lo < hi) {
            int mid = lo + (hi-lo)/2;
            if (td.is_ancestor(td.chains[p][mid], v))
               hi = mid;
            else
               lo = mid+1;
         }
         hi = lo;
         lo = td.node_chain_pos[u].second; // restore lo
      }
      res += segm_trees[p].count(lo, hi-1);
      u = td.chains[p][hi];
   }
   return res;
}

struct Road {
   int u, v;
};

Road roads[100004];

int main(int argc, char* argv[]) {
   cin.sync_with_stdio(false);
   int N;
   cin >> N;
   TreeDecomposition td(N);
   for (int j = 1; j < N; ++j) {
      int u, v;
      cin >> u >> v;
      --u, --v;
      roads[j].u = u;
      roads[j].v = v;
      td.adj[u].push_back(v);
      td.adj[v].push_back(u);
   }

   td.decompose();

   segm_trees.clear();
   for (int i = 0; i < int(td.chains.size()); ++i)
      segm_trees.push_back(
         SegmentTree( int(td.chains[i].size())-1 ) );

   int Q;
   cin >> Q;
   for (int q = 1; q <= Q; ++q) {
      int u, v;
      cin >> u >> v;
      --u, --v;
      if (u == v) continue;
      update(td, u, v);
   }

   for (int j = 1; j < N; ++j) {
      llong res = query(td, roads[j].u, roads[j].v);
      cout << res << "\n";
   }

   return 0;
}


// LCA(Lowest Common Ancestor)
class LCA
{
    friend class LCABuilder;
    friend LCA build_lca(vector<vector<int> >& g, int root);

private:
    int max_log;

    LCA(vector<int>& depth, vector<vector<int> >& parent, int max_log)
        : depth(depth), parent(parent), max_log(max_log) { }

public:
    vector<int> depth;
    vector<vector<int> > parent;

    int lca(int u, int v)
    {
        if (depth[u] > depth[v])
            swap(u, v);

        for (int k = 0; k < max_log; ++k)
            if ((depth[v] - depth[u]) >> k & 1)
                v = parent[k][v];

        if (u == v)
            return u;

        for (int k = max_log - 1; k >= 0; --k)
        {
            if (parent[k][u] != parent[k][v])
            {
                u = parent[k][u];
                v = parent[k][v];
            }
        }

        return parent[0][u];
    }
};
class LCABuilder
{
    friend LCA build_lca(vector<vector<int> >& g, int root);

private:
    int root, n;
    vector<vector<int> >& g;

    int max_log;
    vector<int> depth;
    vector<vector<int> > parent;

    LCABuilder(vector<vector<int> >& graph, int root)
        : g(graph), n(graph.size()), depth(n), root(root)
    {
        max_log = 0;
        for (int i = 1; i < n; i *= 2)
            ++max_log;
        parent = vector<vector<int> >(max_log, vector<int>(n));

        init();
    }

    void calc_depth(int v, int p, int d)
    {
        parent[0][v] = p;
        depth[v] = d;

        for (int i = 0; i < g[v].size(); ++i)
            if (g[v][i] != p)
                calc_depth(g[v][i], v, d + 1);
    }

    void init()
    {
        calc_depth(root, -1, 0);

        for (int k = 0; k + 1 < max_log; ++k)
        {
            for (int v = 0; v < n; ++v)
            {
                if (parent[k][v] < 0)
                    parent[k + 1][v] = -1;
                else
                    parent[k + 1][v] = parent[k][parent[k][v]];
            }
        }
    }
};
LCA build_lca(vector<vector<int> >& g, int root)
{
    LCABuilder builder(g, root);
    return LCA(builder.depth, builder.parent, builder.max_log);
}


#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <climits>
#include <cfloat>
#include <ctime>
#include <cassert>
#include <map>
#include <utility>
#include <set>
#include <iostream>
#include <memory>
#include <string>
#include <vector>
#include <algorithm>
#include <functional>
#include <sstream>
#include <complex>
#include <stack>
#include <queue>
#include <numeric>
#include <list>
#include <iomanip>

using namespace std;

#ifdef _MSC_VER
#define __typeof__ decltype
template <class T> int popcount(T n) { return n ? 1 + popcount(n & (n - 1)) : 0; }
#endif
#ifdef __GNUC__
template <class T> int popcount(T n);
template <> int popcount(unsigned int n) { return n ? __builtin_popcount(n) : 0; }
template <> int popcount(int n) { return n ? __builtin_popcount(n) : 0; }
template <> int popcount(unsigned long long n) { return n ? __builtin_popcountll(n) : 0; }
template <> int popcount(long long n) { return n ? __builtin_popcountll(n) : 0; }
#endif

#define rep (i, n) for (int i = 0; i < (int)n; ++i)
#define foreach(it, c) for (__typeof__((c).begin()) it=(c).begin(); it != (c).end(); ++it)
#define all(c) (c).begin(), (c).end()
#define rall(c) (c).rbegin(), (c).rend()
#define CL(arr, val) memset(arr, val, sizeof(arr))

template <class T> void max_swap(T& a, const T& b) { a = max(a, b); }
template <class T> void min_swap(T& a, const T& b) { a = min(a, b); }

typedef long long ll;
typedef pair<int, int> pint;

const double EPS = 1e-8;
const double PI = acos(-1.0);
const int dx[] = { 0, 1, 0, -1 };
const int dy[] = { 1, 0, -1, 0 };
bool valid_pos(int x, int y, int w, int h) { return 0 <= x && x < w && 0 <= y && y < h; }

template <class T> void print(T a, int n, int br = 1, const string& deli = ", ") { cout << "{ "; for (int i = 0; i < n; ++i) { cout << a[i]; if (i + 1 != n) cout << deli; } cout << " }"; while (br--) cout << endl; }
template <class T> void print(const vector<T>& v, int br = 1, const string& deli = ", ") { print(v, v.size(), br, deli); }

// LCA(Lowest Common Ancestor)
class LCA
{
    friend class LCABuilder;
    friend LCA build_lca(vector<vector<int> >& g, int root);

private:
    int max_log;

    LCA(vector<int>& depth, vector<vector<int> >& parent, int max_log)
        : depth(depth), parent(parent), max_log(max_log) { }

public:
    vector<int> depth;
    vector<vector<int> > parent;

    int lca(int u, int v)
    {
        if (depth[u] > depth[v])
            swap(u, v);

        for (int k = 0; k < max_log; ++k)
            if ((depth[v] - depth[u]) >> k & 1)
                v = parent[k][v];

        if (u == v)
            return u;

        for (int k = max_log - 1; k >= 0; --k)
        {
            if (parent[k][u] != parent[k][v])
            {
                u = parent[k][u];
                v = parent[k][v];
            }
        }

        return parent[0][u];
    }
};
class LCABuilder
{
    friend LCA build_lca(vector<vector<int> >& g, int root);

private:
    int root, n;
    vector<vector<int> >& g;

    int max_log;
    vector<int> depth;
    vector<vector<int> > parent;

    LCABuilder(vector<vector<int> >& graph, int root)
        : g(graph), n(graph.size()), depth(n), root(root)
    {
        max_log = 0;
        for (int i = 1; i < n; i *= 2)
            ++max_log;
        parent = vector<vector<int> >(max_log, vector<int>(n));

        init();
    }

    void calc_depth(int v, int p, int d)
    {
        parent[0][v] = p;
        depth[v] = d;

        for (int i = 0; i < g[v].size(); ++i)
            if (g[v][i] != p)
                calc_depth(g[v][i], v, d + 1);
    }

    void init()
    {
        calc_depth(root, -1, 0);

        for (int k = 0; k + 1 < max_log; ++k)
        {
            for (int v = 0; v < n; ++v)
            {
                if (parent[k][v] < 0)
                    parent[k + 1][v] = -1;
                else
                    parent[k + 1][v] = parent[k][parent[k][v]];
            }
        }
    }
};
LCA build_lca(vector<vector<int> >& g, int root)
{
    LCABuilder builder(g, root);
    return LCA(builder.depth, builder.parent, builder.max_log);
}

vector<vector<int> > g;

int end[114514];
int go_on[114514];
int recur(int v, int p)
{
    int res = end[v];
    for (int i = 0; i < g[v].size(); ++i)
        if (g[v][i] != p)
            res += recur(g[v][i], v);
    return go_on[v] = res;
}
int main()
{
    ios::sync_with_stdio(false);

    int n;
    static int a[114514], b[114514];

    cin >> n;
    g.resize(n + 1);
    for (int i = 0; i < n - 1; ++i)
    {
        cin >> a[i] >> b[i];
        g[a[i]].push_back(b[i]);
        g[b[i]].push_back(a[i]);
    }

    LCA lca = build_lca(g, 1);

    int k;
    cin >> k;
    while (k--)
    {
        int x, y;
        cin >> x >> y;

        ++end[x];
        ++end[y];
        end[lca.lca(x, y)] -= 2;
    }

    recur(1, -1);

    for (int i = 0; i < n - 1; ++i)
    {
        int x = a[i], y = b[i];
        if (lca.depth[x] < lca.depth[y])
            swap(x, y);

        cout << go_on[x] << endl;
    }
}


#include <iostream>
#include <iomanip>
#include <sstream>
#include <algorithm>
#include <cmath>
#include <climits>
#include <limits.h>
#include <string>
#include <stack>
#include <vector>
#include <set>
#include <map>
#include <queue>
#include <assert.h>
#include <cstring>
#include <bitset>
using namespace std;
#define rep(i, n) for (int (i) = 0, j123 = n; (i) < j123; (i) ++)
#define rep1(i, n) for (int (i) = 1, j123 = n; (i) <= j123; (i) ++)
#define db(x) {cout << #x << " = " << (x) << endl;}
#define dba(a, x, y) {cout << #a << " :";for(int i123=(x);i123<=(y);i123++) cout<<setw(4)<<(a)[i123];cout<<endl;}
#define clr(x) memset(x,0,sizeof(x));
#define mp make_pair
#define pb push_back
#define sz(x) int(x.size())
#define endl '\n'
typedef long long ll;
typedef long double ld;
const int INF = INT_MAX;
const ll INFL = LLONG_MAX;
const ld pi = acos(-1);
// const int MOD = ;

/*
 * LCA. Each query is O(log N)
 * Initialization is O(N log N)
 * 3 values to set
 * root, MAX_V, MAX_LOG_V
 */
const int MAX_V = 100100;
const int MAX_LOG_V = 20;

vector<int> adj[MAX_V];
int root;

int parent[MAX_LOG_V][MAX_V];
int depth[MAX_V];

void dfs(int u, int p, int d)
{
  parent[0][u] = p;
  depth[u] = d;
  rep(i,sz(adj[u]))
  {
    int v = adj[u][i];
    if (v == p) continue;
    dfs(v, u, d+1);
  }
}

// V is the max node number
void init(int V)
{
  dfs(root, -1, 0);
  for (int k = 0; k + 1 < MAX_LOG_V; k++)
  {
    rep(v,V+1)
    {
      if (parent[k][v] < 0) parent[k+1][v] = -1;
      else parent[k+1][v] = parent[k][parent[k][v]];
    }
  }
}

int lca(int u, int v)
{
  if (depth[u] > depth[v]) swap(u, v);
  rep(k,MAX_LOG_V)
  {
    if ((depth[v] - depth[u]) >> k & 1)
    {
      v = parent[k][v];
    }
  }
  if (u == v) return u;
  for (int k = MAX_LOG_V-1; k >= 0; k--)
  {
    if (parent[k][u] != parent[k][v])
    {
      u = parent[k][u];
      v = parent[k][v];
    }
  }
  return parent[0][u];
}

/*
 * LCA ends here
 */

int N,K;
int from[100100];
int to[100100];
map<int,int> cost[100100];
int cc = 0;
int mydfs(int u, int p)
{
  cc++;
  if (cc >= 1000)
  {
    exit(0);
  }
  rep(i,sz(adj[u]))
  {
    int v = adj[u][i];
    if (v == p) continue;
    mydfs(v,u);
  }
  rep(i,sz(adj[u]))
  {
    int v = adj[u][i];
    if (v == p) continue;
    if (p != -1) cost[p][u] += cost[u][v];
  }
}
int main()
{
  ios_base::sync_with_stdio(0); cout.precision(15); cout << fixed; cout.tie(0); cin.tie(0);
  cin >> N;
  rep1(i,N-1)
  {
    int u, v;
    cin >> u >> v;
    adj[u].pb(v);
    adj[v].pb(u);
    from[i] = u;
    to[i] = v;
  }
  root = 1;
  init(N);
  cin >> K;
  rep1(qIndex,K)
  {
    int u, v;
    cin >> u >> v;
    if (u == v) continue;
//    continue;
    int anc = lca(u,v);
//    continue;
    if (depth[u] > depth[v]) swap(u,v);
//    db(u);
//    db(v);
//    db(anc);
//    cout << endl;
    if (anc == u)
    {
      if (parent[0][anc]>=0)
        cost[parent[0][anc]][anc]--;
      cost[parent[0][v]][v]++;
    }
    else
    {
      if (parent[0][anc]>=0)
        cost[parent[0][anc]][anc]-=2;
      cost[parent[0][u]][u]++;
      cost[parent[0][v]][v]++;
    }
  }
  mydfs(1,-1);
  vector<int> ans;
  rep1(i,N-1)
  {
    int u = from[i];
    int v = to[i];
    if (parent[0][u] == v)
      swap(u,v);
    // u
    // |
    // v
    ans.pb(cost[u][v]);
  }
  rep(i,sz(ans))
  cout << ans[i] << (i+1<sz(ans)?' ':'\n');
}


#include <iostream>
#include <iomanip>
#include <sstream>
#include <algorithm>
#include <cmath>
#include <climits>
#include <limits.h>
#include <string>
#include <stack>
#include <vector>
#include <set>
#include <map>
#include <queue>
#include <assert.h>
#include <cstring>
#include <bitset>
using namespace std;
#define rep(i, n) for (int (i) = 0, j123 = n; (i) < j123; (i) ++)
#define rep1(i, n) for (int (i) = 1, j123 = n; (i) <= j123; (i) ++)
#define db(x) {cout << #x << " = " << (x) << endl;}
#define dba(a, x, y) {cout << #a << " :";for(int i123=(x);i123<=(y);i123++) cout<<setw(4)<<(a)[i123];cout<<endl;}
#define clr(x) memset(x,0,sizeof(x));
#define mp make_pair
#define pb push_back
#define sz(x) int(x.size())
#define endl '\n'
typedef long long ll;
typedef long double ld;
const int INF = INT_MAX;
const ll INFL = LLONG_MAX;
const ld pi = acos(-1);
// const int MOD = ;

/*
 * LCA. Each query is O(log N)
 * Initialization is O(N log N)
 * 3 values to set
 * root, MAX_V, MAX_LOG_V
 */
const int MAX_V = 100100;
const int MAX_LOG_V = 20;

vector<int> adj[MAX_V];
int root;

int parent[MAX_LOG_V][MAX_V];
int depth[MAX_V];

void dfs(int u, int p, int d)
{
  parent[0][u] = p;
  depth[u] = d;
  rep(i,sz(adj[u]))
  {
    int v = adj[u][i];
    if (v == p) continue;
    dfs(v, u, d+1);
  }
}

// V is the max node number
void init(int V)
{
  dfs(root, -1, 0);
  for (int k = 0; k + 1 < MAX_LOG_V; k++)
  {
    rep(v,V+1)
    {
      if (parent[k][v] < 0) parent[k+1][v] = -1;
      else parent[k+1][v] = parent[k][parent[k][v]];
    }
  }
}

int lca(int u, int v)
{
  if (depth[u] > depth[v]) swap(u, v);
  rep(k,MAX_LOG_V)
  {
    if ((depth[v] - depth[u]) >> k & 1)
    {
      v = parent[k][v];
    }
  }
  if (u == v) return u;
  for (int k = MAX_LOG_V-1; k >= 0; k--)
  {
    if (parent[k][u] != parent[k][v])
    {
      u = parent[k][u];
      v = parent[k][v];
    }
  }
  return parent[0][u];
}

/*
 * LCA ends here
 */

int N,K;
int from[100100];
int to[100100];
map<int,int> cost[100100];
int cc = 0;
int mydfs(int u, int p)
{
//  cc++;
//  if (cc >= 1000)
//  {
//    exit(0);
//  }
  rep(i,sz(adj[u]))
  {
    int v = adj[u][i];
    if (v == p) continue;
    mydfs(v,u);
  }
  rep(i,sz(adj[u]))
  {
    int v = adj[u][i];
    if (v == p) continue;
    if (p != -1) cost[p][u] += cost[u][v];
  }
}
int main()
{
  ios_base::sync_with_stdio(0); cout.precision(15); cout << fixed; cout.tie(0); cin.tie(0);
  cin >> N;
  rep1(i,N-1)
  {
    int u, v;
    cin >> u >> v;
    adj[u].pb(v);
    adj[v].pb(u);
    from[i] = u;
    to[i] = v;
  }
  root = 1;
  init(N);
  cin >> K;
  rep1(qIndex,K)
  {
    int u, v;
    cin >> u >> v;
    if (u == v) continue;
//    continue;
    int anc = lca(u,v);
//    continue;
    if (depth[u] > depth[v]) swap(u,v);
//    db(u);
//    db(v);
//    db(anc);
//    cout << endl;
    if (anc == u)
    {
      if (parent[0][anc]>=0)
        cost[parent[0][anc]][anc]--;
      cost[parent[0][v]][v]++;
    }
    else
    {
      if (parent[0][anc]>=0)
        cost[parent[0][anc]][anc]-=2;
      cost[parent[0][u]][u]++;
      cost[parent[0][v]][v]++;
    }
  }
  mydfs(1,-1);
  vector<int> ans;
  rep1(i,N-1)
  {
    int u = from[i];
    int v = to[i];
    if (parent[0][u] == v)
      swap(u,v);
    // u
    // |
    // v
    ans.pb(cost[u][v]);
  }
  rep(i,sz(ans))
  cout << ans[i] << (i+1<sz(ans)?' ':'\n');
}


#include <bits/stdc++.h>
#define int long long
#define MAXN 100005
using namespace std;
inline int read(){
    int x=0ll,f=1ll;
    char ch=getchar();
    while (ch<'0'||ch>'9'){
        if (ch=='-') f=-1ll;
        ch=getchar();
    }
    while (ch>='0'&&ch<='9'){
        x=(x<<1ll)+(x<<3ll)+(ch-'0');
        ch=getchar();
    }
    return x*f;
}
multiset<int>ans,Son[MAXN];
int A[MAXN];//i和A[i]连边
int B[MAXN];//节点权值
int E[MAXN];
int F[MAXN];//除去E[A[i]]后的C[i]，即i自己和进入C[i]的点分给i的糖果
int in[MAXN];//入度
int Sum[MAXN];//连进i的节点的F值，比较迷
inline void Update(int i){
    E[i]=B[i]/(in[i]+2);//入度+2等于要分给多少点
    F[i]=B[i]-(in[i]+1)*E[i];
}
#define Iter multiset<long long>::iterator
inline int End(multiset<int>&P){
    Iter it=P.end();it--;
    return *it;
}
inline int Begin(multiset<int>&P){
    Iter it=P.begin();
    return *it;
}
inline void DelAns(int i){
    if (Son[i].size()==0) return ;
    ans.erase(ans.find(Begin(Son[i])+E[i]));
    ans.erase(ans.find(End(Son[i])+E[i]));
    //从结果中删去max(Son[i])+E[i]和min(Son[i])+E[i]
}
inline void AddAns(int i){
    if (Son[i].size()==0) return ;
    ans.insert(Begin(Son[i])+E[i]);
    ans.insert(End(Son[i])+E[i]);
}

inline void AddSon(int i){
    Son[A[i]].insert(F[i]+Sum[i]);
}
inline void DelSon(int i){
    Son[A[i]].erase(Son[A[i]].find(F[i]+Sum[i]));
}

#undef int
int main(){
#define int long long
    int n=read(),q=read();
    for (register int i=1;i<=n;++i){
        B[i]=read();
    }
    memset(in,0,sizeof(in));
    for (register int i=1;i<=n;++i){
        A[i]=read();
        in[A[i]]++;
    }
    for (register int i=1;i<=n;++i){
        Update(i);
        Sum[A[i]]+=E[i];
    }
    for (register int i=1;i<=n;++i){
        AddSon(i);
    }
    for (register int i=1;i<=n;++i){
        AddAns(i);
    }
    while (q--){
        int opr=read();
        if (opr==1){
            int i=read(),j=read();

            if (A[i]==j) continue;

            DelAns(A[i]),DelAns(A[A[i]]),DelAns(A[A[A[i]]]);
            DelSon(i),DelSon(A[i]),DelSon(A[A[i]]);

            in[A[i]]--;
            Sum[A[i]]-=E[i];
            Sum[A[A[i]]]-=E[A[i]];
            Update(A[i]);
            Sum[A[A[i]]]+=E[A[i]];

            AddSon(A[i]),AddSon(A[A[i]]);
            AddAns(A[i]),AddAns(A[A[i]]),AddAns(A[A[A[i]]]);

            A[i]=j;

            DelAns(A[i]),DelAns(A[A[i]]),DelAns(A[A[A[i]]]);
            DelSon(A[i]),DelSon(A[A[i]]);

            in[A[i]]++;
            Sum[A[i]]+=E[i];
            Sum[A[A[i]]]-=E[A[i]];
            Update(A[i]);
            Sum[A[A[i]]]+=E[A[i]];

            AddSon(i),AddSon(A[i]),AddSon(A[A[i]]);
            AddAns(A[i]),AddAns(A[A[i]]),AddAns(A[A[A[i]]]);
        }
        else if (opr==2){
            int i=read();
            printf("%lld\n",Sum[i]+F[i]+E[A[i]]);
        }
        else {
            printf("%lld %lld\n",Begin(ans),End(ans));
        }
    }
}


#include <bits/stdc++.h>
#define int long long
#define MAXN 100005
using namespace std;
inline int read(){
    int x=0,f=1;
    char ch=getchar();
    while (ch<'0'||ch>'9'){
        if (ch=='-') f=-1;
        ch=getchar();
    }
    while (ch>='0'&&ch<='9'){
        x=(x<<1)+(x<<3)+(ch^'0');
        ch=getchar();
    }
    return x*f;
}
multiset<int>ans,Son[MAXN];
int A[MAXN];//i和A[i]连边
int B[MAXN];//节点权值
int E[MAXN];
int F[MAXN];//除去E[A[i]]后的C[i]，即i自己和进入C[i]的点分给i的糖果
int in[MAXN];//入度
int Sum[MAXN];//连进i的节点的F值，比较迷
inline void UpdateE(int i){
    E[i]=B[i]/(in[i]+2);//入度+2等于要分给多少点
}
inline void UpdateF(int i){
    F[i]=B[i]-(B[i]/(in[i]+2))*(in[i]+1);
}
#define Iter set<int>::iterator
inline int End(multiset<int>P){
    Iter it=P.end();it--;
    return *it;
}
inline int Begin(multiset<int>P){
    Iter it=P.begin();
    return *it;
}
inline void DelAns(int i){
    if (Son[i].size()==0) return ;
    ans.erase(ans.find(Begin(Son[i])+E[i]));
    ans.erase(ans.find(End(Son[i])+E[i]));
    //从结果中删去max(Son[i])+E[i]和min(Son[i])+E[i]
}
inline void AddAns(int i){
    if (Son[i].size()==0) return ;
    ans.insert(Begin(Son[i])+E[i]);
    ans.insert(End(Son[i])+E[i]);
}

inline void AddSon(int i){
   //printf("-------------%d\n",i);
    Son[A[i]].insert(E[i]+Sum[i]);
}
inline void DelSon(int i){
    Son[A[i]].erase(Son[A[i]].find(E[i]+Sum[i]));
}

#undef int
int main(){
#define int long long
    int n=read(),q=read();
    for (register int i=1;i<=n;++i){
        B[i]=read();
    }
    for (register int i=1;i<=n;++i){
        A[i]=read();
        in[A[i]]++;
    }
    for (register int i=1;i<=n;++i){
        UpdateE(i);UpdateF(i);
        Sum[A[i]]+=E[i];
    }
    for (register int i=1;i<=n;++i){
        AddSon(i);
    }
    for (register int i=1;i<=n;++i){
        AddAns(i);
    }
    while (q--){
        int opr=read();
        if (opr==1){
            int i=read(),j=read();

            if (A[i]==j) continue;

            DelAns(A[i]),DelAns(A[A[i]]),DelAns(A[A[A[i]]]);
            DelSon(i),DelSon(A[i]),DelSon(A[A[i]]);

            in[A[i]]--;
            Sum[A[i]]-=E[i];
            Sum[A[A[i]]]-=E[A[i]];
            UpdateE(A[i]),UpdateF(A[i]);
            Sum[A[A[i]]]+=E[A[i]];

            AddSon(A[i]),AddSon(A[A[i]]);
            AddAns(A[i]),AddAns(A[A[i]]),AddAns(A[A[A[i]]]);

            A[i]=j;

            DelAns(A[i]),DelAns(A[A[i]]),DelAns(A[A[A[i]]]);
            DelSon(A[i]),DelSon(A[A[i]]);

            in[A[i]]++;
            Sum[A[i]]+=E[i];
            Sum[A[A[i]]]-=E[A[i]];
            UpdateE(A[i]),UpdateF(A[i]);
            Sum[A[A[i]]]+=E[A[i]];

            AddSon(i),AddSon(A[i]),AddSon(A[A[i]]);
            AddAns(A[i]),AddAns(A[A[i]]),AddAns(A[A[A[i]]]);
        }
        else if (opr==2){
            int i=read();
            printf("%lld\n",Sum[i]+F[i]+E[A[i]]);
        }
        else {
            printf("%lld %lld\n",Begin(ans),End(ans));
        }
    }
}


#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+5;
int n,m;
int b[maxn],f[maxn],g[maxn],num[maxn],e[maxn],gg[maxn];
multiset<int>son[maxn],ans;//son 维护儿子信息
multiset<int>::iterator it;
inline void update_ans(int x)
{
   if (son[x].empty())return;
   it=son[x].begin();
   ans.insert(*it+e[x]);
   it=--son[x].end();
   ans.insert(*it+e[x]);
}
inline void insert(int x){son[f[x]].insert(g[x]+gg[x]);}
inline void calc(int x)
{
	e[x]=b[x]/(num[x]+2);
	g[x]=b[x]-(num[x]+1)*e[x];
}
inline void del(int x){son[f[x]].erase(son[f[x]].find(g[x]+gg[x]));}
inline void del_ans(int x)
{
	if (son[x].empty())return;
	it=son[x].begin();
	ans.erase(ans.find(*it+e[x]));
	it=--son[x].end();
	if (it!=son[x].begin())ans.erase(ans.find(*it+e[x]));//直接给值会全删！！
}
inline void cut(int x)
{
	del_ans(f[x]);del_ans(f[f[x]]);del_ans(f[f[f[x]]]);//ans都被影响
	del(x);del(f[x]);del(f[f[x]]);
	gg[f[f[x]]]-=e[f[x]];
	gg[f[x]]-=e[x];
	num[f[x]]--;
	calc(f[x]);
	gg[f[f[x]]]+=e[f[x]];
	insert(f[x]);insert(f[f[x]]);
	update_ans(f[x]);update_ans(f[f[x]]);update_ans(f[f[f[x]]]);
}
inline void link(int x,int y)
{
	f[x]=y;num[y]++;
	del_ans(y);del_ans(f[y]);del_ans(f[f[y]]);
	del(y);del(f[y]);
	gg[f[y]]-=e[y];
	gg[y]+=e[x];
	calc(y);
	gg[f[y]]+=e[y];
	insert(x);insert(y);insert(f[y]);
	update_ans(y);update_ans(f[y]);update_ans(f[f[y]]);
}
int main()
{
	int i;
	scanf("%d%d",&n,&m);
	for (int i=1;i<=n;i++)scanf("%d",&b[i]);
	for (int i=1;i<=n;i++)
	{
     scanf("%d",&f[i]);
     num[f[i]]++;
    }
    for (i=1;i<=n;i++)calc(i),gg[f[i]]+=e[i];//g为除了父亲，其他对i的贡献
    for (i=1;i<=n;i++)update_ans(i),insert(i);
	for (i=1;i<=m;i++)
	{
		int op,x,y;
		scanf("%d",&op);
		if (op==1){
		   scanf("%d%d",&x,&y);
		   cut(x);
		   link(x,y);
		}else if (op==2){
			scanf("%d",&x);
			printf("%d\n",g[x]+gg[x]+e[f[x]]);
		}else{
			it=ans.begin();
			printf("%d ",*it);
			it=--ans.end();
			printf("%d\n",*it);
		}
	}
	return 0;
}


#include <bits/stdc++.h>
const int maxn=2e5+7;
using namespace std;
multiset<long long> ss1,ss2[maxn];
int fa[maxn];
long long sum[maxn],w[maxn],du[maxn];
long long getsum(int x){
	return w[x]/(du[x]+1);
}
long long getsum1(int x){
	return sum[x]+w[x]-du[x]*(w[x]/(du[x]+1));
}
int main(){
	int n,m;
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++){
		du[i]++;
		scanf("%lld",&w[i]);
	}
	for(int i=1;i<=n;i++){
		scanf("%d",&fa[i]);
		du[fa[i]]++;
	}
	for(int i=1;i<=n;i++){
		int num=fa[i];
		long long sum0=w[num]/(du[num]+1);
		sum[i]+=sum0;
		sum0=w[i]/(du[i]+1);
		sum[fa[i]]+=sum0;
	}
	for(int i=1;i<=n;i++){
		long long sum0=w[fa[i]]/(du[fa[i]]+1);
		//cout<<sum0<<" "<<getsum1(i)<<endl;
		ss2[fa[i]].insert(getsum1(i)-sum0);
	}
	long long mins,maxs;
	for(int i=1;i<=n;i++){
		if(du[i]==1) continue;
		mins=*ss2[i].begin();
		maxs=*(--ss2[i].end());
		long long sum0=w[i]/(du[i]+1);
		//cout<<"------->"<<mins<<" "<<maxs<<endl;
		//cout<<"--->"<<sum0<<endl;
		ss1.insert(mins+sum0);
		ss1.insert(maxs+sum0);
	}
	int ss=getsum(3);
	cout<<getsum1(6)<<" "<<ss<<endl;
	int s,u,v;
	for(int i=1;i<=m;i++){
		multiset <long long>::iterator pos,pos1;
		scanf("%d",&s);
		if(s==1){
			scanf("%d%d",&u,&v);
			long long sum0=getsum(fa[u]),sum1=getsum(u),sum2,Sum;
			// fa1
			//cout<<1<<" !"<<getsum1(6)<<endl;
			int fa1=fa[fa[u]];
			if(ss2[fa1].size()>1){
			mins=*ss2[fa1].begin();
			maxs=*(--ss2[fa1].end());
			Sum=getsum(fa1);
			mins+=Sum,maxs+=Sum;
			pos =ss1.find(mins);
			ss1.erase(pos);
			pos1 =ss1.find(maxs);
			ss1.erase(pos1);
			}
			else if(ss2[fa1].size()){
				mins=*ss2[fa1].begin();
				Sum=getsum(fa1);
				pos=ss1.find(mins+Sum);
				ss1.erase(pos);
			}
			//cout<<2<<" !"<<getsum1(6)<<endl;
			//
			sum2=getsum(fa1);
			sum[fa1]-=sum[fa[u]];
			pos =ss2[fa1].find(getsum1(fa[u])-sum2);
			ss2[fa1].erase(pos);
			sum[fa[u]]-=sum1;
			sum[fa1]+=sum[fa[u]];
			du[fa[u]]--;
			ss2[fa1].insert(getsum1(fa[u])-sum2);
			//cout<<3<<" !"<<getsum1(6)<<endl;
			//
			if(ss2[fa1].size()>1){
			mins=*ss2[fa1].begin();
			maxs=*(--ss2[fa1].end());
			Sum=getsum(fa1);
			mins+=Sum;maxs+=Sum;
			ss1.insert(mins);
			ss1.insert(maxs);
			}
			else if(ss2[fa1].size()){
				mins=*ss2[fa1].begin();
				Sum=getsum(fa1);
				mins+=Sum;
				ss1.insert(mins);
			}
			//cout<<4<<" !"<<getsum1(6)<<endl;
			//fa[u]
			if(ss2[fa[u]].size()>1){
			mins=*ss2[fa[u]].begin();
			maxs=*(--ss2[fa[u]].end());
			du[fa[u]]++;
			Sum=getsum(fa[u]);
			du[fa[u]]--;
			mins+=Sum,maxs+=Sum;
			pos =ss1.find(mins);
			ss1.erase(pos);
			pos1 =ss1.find(maxs);
			ss1.erase(pos1);
			}
			else if(ss2[fa[u]].size()){
				mins=*ss2[fa[u]].begin();
				du[fa[u]]++;
				Sum=getsum(fa[u]);
				du[fa[u]]--;
				pos=ss1.find(mins+Sum);
				ss1.erase(pos);
			}
			//cout<<5<<" !"<<getsum1(6)<<endl;
			//
			pos =ss2[fa[u]].find(getsum1(u)-sum0);
			ss2[fa[u]].erase(pos);
			//cout<<6<<" !"<<getsum1(6)<<endl;
			//
			if(ss2[fa[u]].size()>1){
			mins=*ss2[fa[u]].begin();
			maxs=*(--ss2[fa[u]].end());
			Sum=getsum(fa[u]);
			mins+=Sum;maxs+=Sum;
			ss1.insert(mins);
			ss1.insert(maxs);
		}
			else if(ss2[fa[u]].size()){
				mins=*ss2[fa[u]].begin();
				Sum=getsum(fa[u]);
				ss1.insert(mins+Sum);
			}
			//cout<<7<<" !"<<getsum1(6)<<endl;
			//u
			sum[u]-=sum0;
			fa[u]=v;
			sum0=getsum(fa[u]);
			sum[u]+=sum0;
			long long sum3;
			//cout<<8<<" !"<<getsum1(6)<<endl;
			// fa3
			fa1=fa[fa[u]];
			//
			if(ss2[fa1].size()>1){
			mins=*ss2[fa1].begin();
			maxs=*(--ss2[fa1].end());
			Sum=getsum(fa1);
			mins+=Sum,maxs+=Sum;
			pos =ss1.find(mins);
			ss1.erase(pos);
			pos1 =ss1.find(maxs);
			ss1.erase(pos1);
			}
			else if(ss2[fa1].size()){
				mins=*ss2[fa1].begin();
				Sum=getsum(fa1);
				pos=ss1.find(mins+Sum);
				ss1.erase(pos);
			}
			//cout<<9<<" !"<<getsum1(6)<<endl;
			//
			sum2=getsum(fa1);
			sum[fa1]-=sum[fa[u]];
			pos =ss2[fa1].find(getsum1(fa[u])-sum2);
			//cout<<10<<" !"<<endl;
			ss2[fa1].erase(pos);
			sum[fa[u]]+=sum1;
			du[v]++;
			sum[fa1]+=sum[fa[u]];
			ss2[fa1].insert(getsum1(fa[u])-sum2);
			//
			if(ss2[fa1].size()>1){
			mins=*ss2[fa1].begin();
			maxs=*(--ss2[fa1].end());
			Sum=getsum(fa1);
			mins+=Sum;maxs+=Sum;
			ss1.insert(mins);
			ss1.insert(maxs);
			}
			else if(ss2[fa1].size()){
				mins=*ss2[fa1].begin();
				Sum=getsum(fa1);
				mins+=Sum;
				ss1.insert(mins);
			}
			//
			// fa2
			if(ss2[fa[u]].size()>1){
			mins=*ss2[fa[u]].begin();
			maxs=*(--ss2[fa[u]].end());
			du[v]--;
			Sum=getsum(fa[u]);
			du[v]++;
			mins+=Sum,maxs+=Sum;
			pos =ss1.find(mins);
			ss1.erase(pos);
			pos1 =ss1.find(maxs);
			ss1.erase(pos1);
			}
			else if(ss2[fa[u]].size()){
				mins=*ss2[fa[u]].begin();
				du[v]--;
				Sum=getsum(fa[u]);
				du[v]++;
				pos=ss1.find(mins+Sum);
				ss1.erase(pos);
			}
			//
			sum3=getsum(fa[u]);
			ss2[fa[u]].insert(getsum1(u)-sum3);
			//
			if(ss2[fa[u]].size()>1){
			mins=*ss2[fa[u]].begin();
			maxs=*(--ss2[fa[u]].end());
			Sum=getsum(fa[u]);
			mins+=Sum;maxs+=Sum;
			ss1.insert(mins);
			ss1.insert(maxs);
			}
			else if(ss2[fa[u]].size()){
				mins=*ss2[fa[u]].begin();
				Sum=getsum(fa[u]);
				ss1.insert(mins+Sum);
			}
			//
		}
		if(s==2){
			scanf("%d",&u);
			printf("%lld\n",getsum1(u));
		}
		if(s==3){
			mins=*ss1.begin();
			maxs=*(--ss1.end());
			printf("%lld %lld\n",mins,maxs);
		}
	}
	return 0;
}


#include <iostream>
#include <cstdio>
#include <cctype>
#include <set>
#define il inline
#define vd void
#define ll long long
#define int long long
#define mn 100005
#define P puts("233");
#define rep(i,x,y) for(register int i=x;i<=y;++i)
#define drp(i,x,y) for(register int i=x;i>=y;--i)
using namespace std;
const int Len=2333333;
char buf[Len],*p1=buf,*p2=buf,duf[Len],*q1=duf;
il char gc(); il int rd(); il ll rdl(); il vd pc(char c); il vd rt(ll x); il vd flush();
int n,q,opt,u,v,a[mn],d[mn];
ll b[mn],e[mn],c[mn];
multiset <ll> Smax,Smin,s[mn];
il vd Modify(int u,int k,ll E){
    int f=a[u],p=a[f];
    //P
    //printf("%d %d %d\n",s[p].size(),f,s[f].size());
    Smax.erase(Smax.find(*--s[p].end()+e[p])),Smin.erase(Smin.find(*s[p].begin()+e[p])),
    Smax.erase(Smax.find(*--s[f].end()+e[f])),Smin.erase(Smin.find(*s[f].begin()+e[f])),
    //P
    s[p].erase(s[p].find(c[f])),s[f].erase(s[f].find(c[u])),c[f]-=e[u],
    c[u]+=1ll*(d[u]-1)*e[u],e[u]=b[u]/(d[u]+=k),c[u]-=1ll*(d[u]-1)*e[u]+(1ll*E*(-k)),
    c[f]+=e[u],s[f].insert(c[u]),s[p].insert(c[f]),
    //P
    Smax.insert(*--s[f].end()+e[f]),Smin.insert(*s[f].begin()+e[f]),
    Smax.insert(*--s[p].end()+e[p]),Smin.insert(*s[p].begin()+e[p]);
    //P
}
signed main(){
    n=rd(),q=rd();
    rep(i,1,n) b[i]=rdl(),d[i]=1;
    rep(i,1,n) a[i]=rd(),++d[i],++d[a[i]];
    rep(i,1,n) e[i]=b[i]/d[i],c[i]=b[i]+e[i]-1ll*d[i]*e[i];
    rep(i,1,n) c[a[i]]+=e[i];
    rep(i,1,n) s[a[i]].insert(c[i]);
    rep(i,1,n) if(!s[i].empty())
        Smax.insert(*--s[i].end()+e[i]),Smin.insert(*s[i].begin()+e[i]);
    //rep(i,1,n) printf("%d\n",c[i]+e[a[i]]);
    while(q--){//printf("%d\n",q);
        opt=rd();
        //rep(i,1,n) printf("%lld %lld %lld %lld\n",i,d[i],e[i],c[i]);
        //puts("");
        if(opt==1){
            u=rd(),v=rd(); int f=a[u];
            if(a[u]==v) continue;
            Smax.erase(Smax.find(*--s[f].end()+e[f])),Smin.erase(Smin.find(*s[f].begin()+e[f])),
            Modify(f,-1,e[u]),s[f].erase(s[f].find(c[u]));//P
            //printf("%d\n",s[f].size());1
            if(!s[f].empty()) Smax.insert(*--s[f].end()+e[f]),Smin.insert(*s[f].begin()+e[f]);
            if(!s[v].empty()) Smax.erase(Smax.find(*--s[v].end()+e[v])),Smin.erase(Smin.find(*s[v].begin()+e[v]));
            //0;
            //rep(i,1,n) printf("%d %d %d\n",i,e[i],c[i]);
            //puts("");
            //P
            Modify(v,1,e[u]),s[v].insert(c[u]), //P
            Smax.insert(*--s[v].end()+e[v]),Smin.insert(*s[v].begin()+e[v]),a[u]=v;
        }
        else if(opt==2) u=rd(),rt(c[u]+e[a[u]]),pc('\n');
        else rt(*Smin.begin()),pc(' '),rt(*--Smax.end()),pc('\n');
        //flush(),q1=duf;
        //rep(i,1,n) printf("%d ",d[i]); puts("");
    }
    return flush(),0;
}

il char gc(){return p1==p2&&(p2=(p1=buf)+fread(buf,1,Len,stdin),p1==p2)?-1:*p1++;}
il int rd(){char c;
    while(!isdigit(c=gc())&&c!='-');
    int f=c=='-'?c=gc(),1:0,x=c^48;
    while(isdigit(c=gc())) x=((x+(x<<2))<<1)+(c^48);
    return f?-x:x;
}
il ll rdl(){char c;
    while(!isdigit(c=gc())&&c!='-');
    ll f=c=='-'?c=gc(),1:0,x=c^48;
    while(isdigit(c=gc())) x=((x+(x<<2))<<1)+(c^48);
    return f?-x:x;
}
il vd pc(char c){q1==duf+Len&&fwrite(q1=duf,1,Len,stdout),*q1++=c;}
il vd rt(ll x){x<0?pc('-'),x=-x:0,pc((x>=10?rt(x/10),x%10:x)+48);}
il vd flush(){fwrite(duf,1,q1-duf,stdout);}


#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cassert>
#include <set>
#include <ios>

using namespace std;

#define A first
#define B second

typedef long long ll;
typedef pair<ll, ll> pll;

const int maxn = 100100;

int n, q;
ll t[maxn], s[maxn];
int f[maxn], k[maxn];
set<pll> S, T[maxn];

ll ct1(int i) { return t[i] - (k[i] - 1) * (t[i] / k[i]); }
ll ct2(int i) { return t[i] / k[i]; }
ll val(int i) { return s[i] + ct2(f[i]); }

void upd(int a, int b, int pl) {
    s[b] -= ct1(b);
    s[f[b]] -= ct2(b);
    k[b] += pl;
    s[b] += ct1(b);
    s[f[b]] += ct2(b);
    s[b] += pl * ct2(a);

    if (pl == -1) T[b].erase(pll(s[a], a));
    else T[b].insert(pll(s[a], a));

    S.insert(pll(val(b), b));
    S.insert(pll(val(f[b]), b));

    if (!T[b].empty()) {
        pll p = *T[b].begin();
        S.insert(pll(val(p.B), p.B));

        p = *T[b].rbegin();
        S.insert(pll(val(p.B), p.B));
    }
}

int main() {
    ios_base::sync_with_stdio(0);

    cin >> n >> q;
    for (int i = 0; i < n; i++) cin >> t[i];
    for (int i = 0; i < n; i++) {
        cin >> f[i];
        f[i]--;
        k[f[i]]++;
        k[i] += 2;
    }

    for (int i = 0; i < n; i++) {
        s[i] += ct1(i);
        s[f[i]] += ct2(i);
    }

    for (int i = 0; i < n; i++) {
        S.insert(pll(val(i), i));
        T[f[i]].insert(pll(s[i], i));
    }

    for (int i = 0; i < q; i++) {
        int qtype; cin >> qtype;
        if (qtype == 1) {
            int a, b;
            cin >> a >> b;
            a--, b--;

            upd(a, f[a], -1);
            f[a] = b;
            upd(a, b, 1);

            S.insert(pll(val(a), a));
        } else if (qtype == 2) {
            int a; cin >> a;
            a--;
            cout << val(a) << '\n';
        } else {
            while (1) {
                assert(!S.empty());
                pll p = *S.begin();
                if (val(p.B) != p.A) S.erase(p);
                else break;
            }

            while (1) {
                assert(!S.empty());
                pll p = *S.rbegin();
                if (val(p.B) != p.A) S.erase(p);
                else break;
            }

            cout << S.begin()->A << ' ' << S.rbegin()->A << '\n';
        }
    }
}


#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cassert>
#include <set>
#include <ios>

using namespace std;

#define A first
#define B second

typedef long long ll;
typedef pair<ll, ll> pll;

const int maxn = 100100;

int n, q;
ll t[maxn], s[maxn];
int f[maxn], k[maxn];
set<pll> S, T[maxn];

ll ct1(int i) { return t[i] - (k[i] - 1) * (t[i] / k[i]); }
ll ct2(int i) { return t[i] / k[i]; }
ll val(int i) { return s[i] + ct2(f[i]); }
pll newp(int i) { return pll(val(i), i); }
pll newt(int i) { return pll(s[i], i); }

void ins(int i) {
    if (T[i].empty()) return;
    S.insert(newp(T[i].begin()->B));
    S.insert(newp(T[i].rbegin()->B));
}

void upd(int a, int b, int pl) {
    T[f[b]].erase(newt(b));

    s[b] -= ct1(b);
    s[f[b]] -= ct2(b);
    k[b] += pl;
    s[b] += ct1(b);
    s[f[b]] += ct2(b);
    s[b] += pl * ct2(a);

    if (pl == -1) T[b].erase(newt(a));
    else T[b].insert(newt(a));

    T[f[b]].insert(newt(b));

    S.insert(newp(b));
    S.insert(newp(f[b]));

    ins(b);
    ins(f[b]);
}

int main() {
    ios_base::sync_with_stdio(0);

    cin >> n >> q;
    for (int i = 0; i < n; i++) cin >> t[i];
    for (int i = 0; i < n; i++) {
        cin >> f[i];
        f[i]--;
        k[f[i]]++;
        k[i] += 2;
    }

    for (int i = 0; i < n; i++) {
        s[i] += ct1(i);
        s[f[i]] += ct2(i);
    }

    for (int i = 0; i < n; i++) {
        S.insert(newp(i));
        T[f[i]].insert(newt(i));
    }

    for (int i = 0; i < q; i++) {
        int qtype; cin >> qtype;
        if (qtype == 1) {
            int a, b;
            cin >> a >> b;
            a--, b--;

            upd(a, f[a], -1);
            f[a] = b;
            upd(a, b, 1);

            S.insert(newp(a));
        } else if (qtype == 2) {
            int a; cin >> a;
            a--;
            cout << val(a) << '\n';
        } else {
            while (1) {
                assert(!S.empty());
                pll p = *S.begin();
                if (val(p.B) != p.A) S.erase(p);
                else break;
            }

            while (1) {
                assert(!S.empty());
                pll p = *S.rbegin();
                if (val(p.B) != p.A) S.erase(p);
                else break;
            }

            cout << S.begin()->A << ' ' << S.rbegin()->A << '\n';
        }
    }
}


#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cassert>
#include <set>
#include <ios>

using namespace std;

#define A first
#define B second

typedef long long ll;
typedef pair<ll, ll> pll;

const int maxn = 100100;

int n, q;
ll t[maxn], s[maxn];
int f[maxn], k[maxn];
set<pll> S, T[maxn];

ll ct1(int i) { return t[i] - (k[i] - 1) * (t[i] / k[i]); }
ll ct2(int i) { return t[i] / k[i]; }
ll val(int i) { return s[i] + ct2(f[i]); }
pll newp(int i) { return pll(val(i), i); }
pll newt(int i) { return pll(s[i], i); }

void ins(int i) {
    if (T[i].empty()) return;
    S.insert(newp(T[i].begin()->B));
    S.insert(newp(T[i].rbegin()->B));
}

void upd(int a, int b, int pl) {
    T[f[b]].erase(newt(b));
    T[f[f[b]]].erase(newt(f[b]));

    s[b] -= ct1(b);
    s[f[b]] -= ct2(b);
    k[b] += pl;
    s[b] += ct1(b);
    s[f[b]] += ct2(b);
    s[b] += pl * ct2(a);

    if (pl == -1) T[b].erase(newt(a));
    else T[b].insert(newt(a));

    T[f[b]].insert(newt(b));
    T[f[f[b]]].insert(newt(f[b]));

    S.insert(newp(b));
    S.insert(newp(f[b]));

    ins(b);
    ins(f[b]);
    ins(f[f[b]]);
}

int main() {
    ios_base::sync_with_stdio(0);

    cin >> n >> q;
    for (int i = 0; i < n; i++) cin >> t[i];
    for (int i = 0; i < n; i++) {
        cin >> f[i];
        f[i]--;
        k[f[i]]++;
        k[i] += 2;
    }

    for (int i = 0; i < n; i++) {
        s[i] += ct1(i);
        s[f[i]] += ct2(i);
    }

    for (int i = 0; i < n; i++) {
        S.insert(newp(i));
        T[f[i]].insert(newt(i));
    }

    for (int i = 0; i < q; i++) {
        int qtype; cin >> qtype;
        if (qtype == 1) {
            int a, b;
            cin >> a >> b;
            a--, b--;

            upd(a, f[a], -1);
            f[a] = b;
            upd(a, b, 1);

            S.insert(newp(a));
        } else if (qtype == 2) {
            int a; cin >> a;
            a--;
            cout << val(a) << '\n';
        } else {
            while (1) {
                assert(!S.empty());
                pll p = *S.begin();
                if (val(p.B) != p.A) S.erase(p);
                else break;
            }

            while (1) {
                assert(!S.empty());
                pll p = *S.rbegin();
                if (val(p.B) != p.A) S.erase(p);
                else break;
            }

            cout << S.begin()->A << ' ' << S.rbegin()->A << '\n';
        }
    }
}


#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cassert>
#include <set>
#include <ios>

using namespace std;

#define A first
#define B second

typedef long long ll;
typedef pair<ll, ll> pll;

const int maxn = 100100;

int n, q;
ll t[maxn], s[maxn];
int f[maxn], k[maxn];
set<pll> S, T[maxn];

ll ct1(int i) { return t[i] - (k[i] - 1) * (t[i] / k[i]); }
ll ct2(int i) { return t[i] / k[i]; }
ll val(int i) { return s[i] + ct2(f[i]); }

void upd(int a, int b, int pl) {
    s[b] -= ct1(b);
    s[f[b]] -= ct2(b);
    k[b] += pl;
    s[b] += ct1(b);
    s[f[b]] += ct2(b);
    s[b] += pl * ct2(a);

    if (pl == -1) T[b].erase(pll(s[a], a));
    else T[b].insert(pll(s[a], a));

    S.insert(pll(val(b), b));
    S.insert(pll(val(f[b]), f[b]));

    if (!T[b].empty()) {
        pll p = *T[b].begin();
        S.insert(pll(val(p.B), p.B));

        p = *T[b].rbegin();
        S.insert(pll(val(p.B), p.B));
    }
}

int main() {
    ios_base::sync_with_stdio(0);

    cin >> n >> q;
    for (int i = 0; i < n; i++) cin >> t[i];
    for (int i = 0; i < n; i++) {
        cin >> f[i];
        f[i]--;
        k[f[i]]++;
        k[i] += 2;
    }

    for (int i = 0; i < n; i++) {
        s[i] += ct1(i);
        s[f[i]] += ct2(i);
    }

    for (int i = 0; i < n; i++) {
        S.insert(pll(val(i), i));
        T[f[i]].insert(pll(s[i], i));
    }

    for (int i = 0; i < q; i++) {
        int qtype; cin >> qtype;
        if (qtype == 1) {
            int a, b;
            cin >> a >> b;
            a--, b--;

            upd(a, f[a], -1);
            f[a] = b;
            upd(a, b, 1);

            S.insert(pll(val(a), a));
        } else if (qtype == 2) {
            int a; cin >> a;
            a--;
            cout << val(a) << '\n';
        } else {
            while (1) {
                assert(!S.empty());
                pll p = *S.begin();
                if (val(p.B) != p.A) S.erase(p);
                else break;
            }

            while (1) {
                assert(!S.empty());
                pll p = *S.rbegin();
                if (val(p.B) != p.A) S.erase(p);
                else break;
            }

            cout << S.begin()->A << ' ' << S.rbegin()->A << '\n';
        }
    }
}


#include<algorithm>
#include<cstdio>
#define M 700007
#define N 100001
using namespace std;
inline void Put(long long*s,int&t,const long long v,bool(*cmp)(const long long,const long long))
{
    int u=++t;
    for(s--;1<u&&cmp(v,s[u>>1]);u>>=1)s[u]=s[u>>1];
    s[u]=v;
}
inline void Del(long long*s,int&t,bool(*cmp)(const long long,const long long))
{
    int u=1,v=2;
    for(s--,s[1]=s[t--];v<=t;swap(s[u],s[v]),u=v,v=u<<1)
    {
        if(v<t&&cmp(s[v|1],s[v]))v++;
        if(!cmp(s[v],s[u]))return;
    }
}
int S[N],n;long long g[N];
void del(long long*A,long long*B,int*C,int*D,const int u,const long long v,bool(*cmp)(const long long,const long long))
{
    if(A[S[u]]==v)
    {
        if(u!=n)del(A,B,C,D,n,v+g[u+1],cmp);
        for(Del(A+S[u],C[u],cmp);D[u]&&A[S[u]]==B[S[u]];Del(B+S[u],D[u],cmp))Del(A+S[u],C[u],cmp);
        if(u!=n&&C[u])Put(A+S[n],C[n],A[S[u]]+g[u+1],cmp);
    }
    else Put(B+S[u],D[u],v,cmp);
}
inline void put(long long*A,long long*B,int*C,int*D,const int u,const long long v,bool(*cmp)(const long long,const long long))
{
    if(!C[u])Put(A+S[n],C[n],v+g[u+1],cmp);
    else if(cmp(v,A[S[u]]))del(A,B,C,D,n,A[S[u]]+g[u+1],cmp),Put(A+S[n],C[n],v+g[u+1],cmp);
    Put(A+S[u],C[u],v,cmp);
}
inline bool Min(const long long u,const long long v){return u<v;}
inline bool Max(const long long u,const long long v){return v<u;}
int E[N],F[N],G[N],H[N],a[N],b[N],c[N],d[N],f[N],i,q;long long A[M],B[M],C[M],D[M],e[N],h[N];
inline void del(int u){del(A,B,E,F,f[u]-1,h[u],Min),del(C,D,G,H,f[u]-1,h[u],Max);}
inline void put(int u){put(A,B,E,F,f[u]-1,h[u],Min),put(C,D,G,H,f[u]-1,h[u],Max);}
inline void Del(int u){if(E[u-1])del(A,B,E,F,n,A[S[u-1]]+g[u],Min),del(C,D,G,H,n,C[S[u-1]]+g[u],Max);}
inline void Put(int u){if(E[u-1])Put(A+S[n],E[n],A[S[u-1]]+g[u],Min),Put(C+S[n],G[n],C[S[u-1]]+g[u],Max);}
int u,v,w;
int main()
{
    scanf("%d%d",&n,&q);
    for(i=1;i<=n;i++)scanf("%lld",e+i),d[i]=1;
    for(i=1;i<=n;i++)scanf("%d",f+i),S[f[i]]++,d[f[i]]++,d[i]++;
    for(i=1;i<=q;i++)scanf("%d",a+i),a[i]==1?scanf("%d%d",b+i,c+i),w=f[v=f[u=f[b[i]]]],S[w]++,S[v]++,w=f[v=f[u=c[i]]],S[w]++,S[v]++,S[u]++,swap(f[b[i]],c[i]),0:0,a[i]==2?scanf("%d",b+i):0;
    for(i=q;i;i--)if(a[i]==1)swap(f[b[i]],c[i]);
    for(i=1;i<=n;i++)g[i]=e[i]/d[i],h[i]+=e[i]-(d[i]-1)*g[i],h[f[i]]+=g[i],S[i]+=S[i-1];
    for(i=1;i<=n;i++)Put(A+S[f[i]-1],E[f[i]-1],h[i],Min),Put(C+S[f[i]-1],G[f[i]-1],h[i],Max);
    for(i=1;i<=n;i++)Put(i);
    for(i=1;i<=q;i++)
    if(a[i]==1)
    {
        w=f[v=f[u=b[i]]],del(u),del(v),del(w),Del(v),h[w]-=g[v],h[v]-=g[u];
        h[v]+=--d[v]*g[v],g[v]=e[v]/d[v],h[v]-=(d[v]-1)*g[v],h[w]+=g[v],Put(v),put(w),put(v);
        w=f[v=f[u]=c[i]],del(v),del(w),Del(v),h[w]-=g[v],h[v]+=g[u];
        h[v]+=(d[v]-1)*g[v],g[v]=e[v]/++d[v],h[v]-=(d[v]-1)*g[v],h[w]+=g[v],Put(v),put(w),put(v),put(u);
    }
    else if(a[i]==2)printf("%I64d\n",h[b[i]]+g[f[b[i]]]);
    else if(a[i]==3)printf("%I64d %I64d\n",A[S[n]],C[S[n]]);
    return 0;
}//hellobig_tq


#include <iostream>
#include <cassert>
#include <algorithm>
#include <cstdlib>
#include <cstdio>
#include <vector>
#include <set>
#include <map>
#include <iomanip>
#include <math.h>
#include <unordered_map>
#include <unordered_set>
#include <queue>

#define REP(i, n) for (int i = 0; i < n; ++i)
#define FOR(i, a, b) for (int i = a; i < b; ++i)
#define DB(x) cerr << #x << ": " << x << endl;

using namespace std;

typedef long long LL;
typedef long double LD;

const int MAXN = 100000;
const int MOD = 1000 * 1000 * 1000 + 7;

void solve();

int main()
{
    auto start = clock();
    cout.sync_with_stdio(0);
    cin.tie(0);
    cout.precision(10);
    cout << fixed;

#ifdef HOME
    freopen("biginput.txt", "r", stdin);
    //freopen("input.txt", "r", stdin);
    //freopen("output.txt", "w", stdout);
#endif

    int t = 1;
    //cin >> t;
    while (t--) {
        solve();
    }

    cerr << "\nTime: " << (clock() - start) / 1.0 / CLOCKS_PER_SEC << "\n";

    return 0;
}

int n, q;
vector<LL> t;
vector<int> parent;
vector<int> deg;
vector<LL> aggr;
vector<multiset<LL>> children;
multiset<LL> treeSet;

const LL INF = 1000ll * 1000 * 1000 * 1000 * 1000 * 1000;

void pushToParent(int v, int p, int sign)
{
    LL val = t[v] / (deg[v] + 1);
    aggr[p] += val * sign;
}

LL getValWO(int v) {
    LL val = t[v] - deg[v] * (t[v] / (deg[v] + 1));
    val += aggr[v];
    return val;
}

LL getVal(int v) {
    int p = parent[v];
    assert(p != -1);
    return getValWO(v) + t[p] / (deg[p] + 1);
}

void mutateTreeSet(int v, bool add)
{
    if (!children[v].empty()) {
        LL Min = *children[v].begin();
        LL Max = *children[v].rbegin();
        Min += t[v] / (deg[v] + 1);
        Max += t[v] / (deg[v] + 1);

        if (add) {
            treeSet.insert(Min);
            treeSet.insert(Max);
        } else {
            treeSet.erase(treeSet.find(Min));
            treeSet.erase(treeSet.find(Max));
        }
    }
}

void removeFromTreeSet(int v) { mutateTreeSet(v, false); }
void addToTreeSet(int v) { mutateTreeSet(v, true); }

void removeFromParent(int v)
{
    int p = parent[v];
    assert(p != -1);
    LL val = getValWO(v);
    //cerr << "remove_from_parent: " << val << endl;
    children[p].erase(children[p].find(val));
}

void addToParent(int v)
{
    int p = parent[v];
    assert(p != -1);
    LL val = getValWO(v);
    //cerr << "add_to_parent: " << val << endl;
    children[p].insert(val);
}

void cut(int v)
{
    int p = parent[v];
    assert(p != -1);
    int pp = parent[p];
    assert(pp != -1);
    int ppp = parent[pp];
    assert(ppp != -1);

    removeFromTreeSet(p);
    removeFromTreeSet(pp);
    removeFromTreeSet(ppp);

    removeFromParent(pp);
    removeFromParent(p);
    removeFromParent(v);

    pushToParent(v, p, -1);
    pushToParent(p, pp, -1);
    parent[v] = -1;
    --deg[p];
    pushToParent(p, pp, +1);

    addToParent(p);
    addToParent(pp);

    addToTreeSet(p);
    addToTreeSet(pp);
    addToTreeSet(ppp);
}

void link(int v, int p)
{
    assert(parent[v] == -1);
    int pp = parent[p];
    assert(pp != -1);
    int ppp = parent[pp];
    assert(ppp != -1);

    removeFromTreeSet(p);
    removeFromTreeSet(pp);
    removeFromTreeSet(ppp);

    removeFromParent(pp);
    removeFromParent(p);

    pushToParent(v, p, +1);
    pushToParent(p, pp, -1);
    parent[v] = p;
    ++deg[p];
    pushToParent(p, pp, +1);

    addToParent(v);
    addToParent(p);
    addToParent(pp);

    addToTreeSet(p);
    addToTreeSet(pp);
    addToTreeSet(ppp);
}

void gen()
{
    freopen("biginput.txt", "w", stdout);
    int n = 100;
    int q = 100;
    cout << n << " " << q << endl;
    REP(i, n) {
        cout << rand() % 100 << " ";
    }
    cout << endl;
    vector<int> p(n);
    REP(i, n) {
        p[i] = (i + 1) % n;
        cout << p[i] + 1 << " ";
    }
    cout << endl;
    REP(i, q) {
        int u;
        int v;
        do {
            u = rand() % n;
            v = rand() % n;
        } while (u == v || p[v] == u || p[u] == v);
        cout << 1 << " " << u + 1 << " " << v + 1 << endl;
        p[u] = v;
    }
}

void solve()
{
    //gen();
    //exit(0);
    scanf("%d%d", &n, &q);
    t.resize(n);
    parent.resize(n);
    aggr.assign(n, 0);
    deg.assign(n, 0);
    children.resize(n);
    REP(i, n) {
        scanf("%lld", &t[i]);
    }
    REP(i, n) {
        scanf("%d", &parent[i]);
        --parent[i];
        ++deg[i];
        ++deg[parent[i]];
    }
    REP(i, n) {
        pushToParent(i, parent[i], +1);
    }
    REP(i, n) {
        children[parent[i]].insert(getValWO(i));
    }
    REP(i, n) {
        addToTreeSet(i);
    }
    REP(i, q) {
        int type;
        scanf("%d", &type);
        if (type == 1) {
            int a, b;
            scanf("%d%d", &a, &b);
            --a;
            --b;
            cut(a);
            link(a, b);
        } else if (type == 2) {
            int a;
            scanf("%d", &a);
            --a;
            printf("%lld\n", getVal(a));
        } else if (type == 3) {
            printf("%lld %lld\n", *treeSet.begin(), *treeSet.rbegin());
        }
    }
}


#include <cstdio>
#include <cctype>
#include <algorithm>
#include <cstring>
#include <set>
long long read(){
	register long long x = 0;
	register char f = 1, ch = getchar();
	for (; !isdigit(ch); ch = getchar()) if (ch == '-') f = !f;
	for (; isdigit(ch); ch = getchar()) x = (x << 3) + (x << 1) + (ch ^ '0');
	return f ? x : -x;
}
#define N 100005
int n, Q, a[N];
long long b[N], c[N], d[N], e[N], f[N];
std :: multiset<long long> Son[N], S;
int main(){
	n = read(), Q = read();
	for (register int i = 1; i <= n; ++i)
		b[i] = read(), d[i] = 1;
	for (register int i = 1; i <= n; ++i)
		a[i] = read(), ++d[i], ++d[a[i]];
	for (register int i = 1; i <= n; ++i)
		e[i] = b[i] / d[i], c[i] = b[i] % d[i] + e[i];
	for (register int i = 1; i <= n; ++i)
		c[i] += e[a[i]], c[a[i]] += e[i];
	for (register int i = 1; i <= n; ++i)
		f[i] = c[i] - e[a[i]], Son[a[i]].insert(f[i]);
	for (register int i = 1; i <= n; ++i)
		if (Son[i].size()) S.insert(*Son[i].begin() + e[i]), S.insert(*(--Son[i].end()) + e[i]);
	while (Q--){
		int opt = read();
		if (opt == 1){
			int u = read(), v = read();
			if (a[u] == v) continue;
			S.erase(S.find(*Son[a[u]].begin() + e[a[u]])), S.erase(S.find(*(--Son[a[u]].end()) + e[a[u]]));
			Son[a[u]].erase(Son[a[u]].find(f[u]));
			S.erase(S.find(*Son[a[a[u]]].begin() + e[a[a[u]]])), S.erase(S.find(*(--Son[a[a[u]]].end()) + e[a[a[u]]]));
			Son[a[a[u]]].erase(Son[a[a[u]]].find(f[a[u]]));
			S.erase(S.find(*Son[a[a[a[u]]]].begin() + e[a[a[a[u]]]])), S.erase(S.find(*(--Son[a[a[a[u]]]].end()) + e[a[a[a[u]]]]));
			Son[a[a[a[u]]]].erase(Son[a[a[a[u]]]].find(f[a[a[u]]]));
			f[a[u]] = f[a[u]] - e[a[u]] - e[u] - b[a[u]] % d[a[u]], f[a[a[u]]] -= e[a[u]];
			--d[a[u]], e[a[u]] = b[a[u]] / d[a[u]], f[a[u]] += e[a[u]] + b[a[u]] % d[a[u]], f[a[a[u]]] += e[a[u]];
//			printf("f[a[u]]=%d f[a[a[u]]]=%d d[a[u]]=%d e[a[u]]=%d\n", f[a[u]], f[a[a[u]]], d[a[u]], e[a[u]]);
			Son[a[a[u]]].insert(f[a[u]]);
			if (Son[a[u]].size()) S.insert(*Son[a[u]].begin() + e[a[u]]), S.insert(*(--Son[a[u]].end()) + e[a[u]]);
			S.insert(*Son[a[a[u]]].begin() + e[a[a[u]]]), S.insert(*(--Son[a[a[u]]].end()) + e[a[a[u]]]);
			Son[a[a[a[u]]]].insert(f[a[a[u]]]);
			S.insert(*Son[a[a[a[u]]]].begin() + e[a[a[a[u]]]]), S.insert(*(--Son[a[a[a[u]]]].end()) + e[a[a[a[u]]]]);
			a[u] = v;
			if (Son[a[u]].size()) S.erase(S.find(*Son[a[u]].begin() + e[a[u]])), S.erase(S.find(*(--Son[a[u]].end()) + e[a[u]]));
			Son[a[u]].insert(f[u]);
			S.erase(S.find(*Son[a[a[u]]].begin() + e[a[a[u]]])), S.erase(S.find(*(--Son[a[a[u]]].end()) + e[a[a[u]]]));
			Son[a[a[u]]].erase(Son[a[a[u]]].find(f[a[u]]));
			S.erase(S.find(*Son[a[a[a[u]]]].begin() + e[a[a[a[u]]]])), S.erase(S.find(*(--Son[a[a[a[u]]]].end()) + e[a[a[a[u]]]]));
			Son[a[a[a[u]]]].erase(Son[a[a[a[u]]]].find(f[a[a[u]]]));
			f[a[u]] = f[a[u]] - e[a[u]] - b[a[u]] % d[a[u]], f[a[a[u]]] -= e[a[u]];
			++d[a[u]], e[a[u]] = b[a[u]] / d[a[u]], f[a[u]] += e[u] + e[a[u]] + b[a[u]] % d[a[u]], f[a[a[u]]] += e[a[u]];
//			printf("f[a[u]]=%d f[a[a[u]]]=%d d[a[u]]=%d e[a[u]]=%d\n", f[a[u]], f[a[a[u]]], d[a[u]], e[a[u]]);
			Son[a[a[u]]].insert(f[a[u]]);
			S.insert(*Son[a[u]].begin() + e[a[u]]), S.insert(*(--Son[a[u]].end()) + e[a[u]]);
			S.insert(*Son[a[a[u]]].begin() + e[a[a[u]]]), S.insert(*(--Son[a[a[u]]].end()) + e[a[a[u]]]);
			Son[a[a[a[u]]]].insert(f[a[a[u]]]);
			S.insert(*Son[a[a[a[u]]]].begin() + e[a[a[a[u]]]]), S.insert(*(--Son[a[a[a[u]]]].end()) + e[a[a[a[u]]]]);
		}
		if (opt == 2){
			int u = read();
			printf("%lld\n", e[a[u]] + f[u]);
		}
		if (opt == 3) printf("%lld %lld\n", *S.begin(), *(--S.end()));
	}
}