思路是先整体二分求最后一次有用的时间,然后再用 set 维护每个颜色有贡献的 dfs 序的段,用树状数组维护,但是 Wa 了,很多点答案大了 1。
#include <bits/stdc++.h>
#define rep(i, x, y) for (int i = x; i <= y; ++i)
#define drep(i, x, y) for (int i = x; i >= y; --i)
#define ll long long
#define pb push_back
#define IOS ios::sync_with_stdio(false), cin.tie(0), cout.tie(0)
using namespace std;
const int N = 200020;
int n, m, b[N], c[N], h[N * 10];
int dfn[N], tr[N], id[N], ti[N], t[N], ans[N * 10];
vector<int> G[N]; vector<int> d[N * 10];
void dfs(int u, int f) {
dfn[u] = ++*dfn, id[dfn[u]] = u;
for(int v : G[u]) if(v ^ f) dfs(v, u);
tr[u] = *dfn; }
inline void upd(int x, int y) { for(int i = x; i < N; i += (i & -i)) t[i] += y; }
inline void upd(int l, int r, int x) { upd(l, x), upd(r + 1, -x); }
inline int qry(int r) { int v = 0; for(; r; r -= (r & -r)) v += t[r]; return v; }
inline void solve(int l, int r, vector<int> p) {
if(!p.size()) return;
if(l == r) { for(int x : p) ti[x] = l; return; }
int mid = (l + r) >> 1; vector<int> pl, pr;
rep(i, l, mid) upd(dfn[h[i]], 1);
for(int x : p) { int y = qry(tr[x]) - qry(dfn[x] - 1); if(y <= b[x]) b[x] -= y, pr.pb(x); else pl.pb(x); }
rep(i, l, mid) upd(dfn[h[i]], -1);
solve(l, mid, pl), solve(mid + 1, r, pr);
}
set<int> s[N];
inline void ins(int c, int x) {
auto p = s[c].lower_bound(dfn[x]); vector<int> vec;
while(p != s[c].end() && *p <= tr[x]) vec.pb(id[*p]), ++p;
for(int u : vec) upd(dfn[u], tr[u], -1), s[c].erase(dfn[u]);
s[c].insert(dfn[x]), upd(dfn[x], tr[x], 1);
}
int main() {
IOS; cin >> n >> m;
rep(i, 1, n) cin >> b[i]; rep(i, 1, n) cin >> c[i]; rep(i, 1, m) cin >> h[i];
rep(i, 2, n) { int u, v; cin >> u >> v; G[u].pb(v), G[v].pb(u); }
dfs(1, 0); vector<int> all; rep(i, 1, n) if(b[i]) all.pb(i); solve(1, m + 1, all);
rep(i, 1, n) if(ti[i]) d[ti[i] - 1].pb(i);
drep(i, m, 1) {
for(int j : d[i]) ins(c[j], j);
ans[i] = qry(dfn[h[i]]);
}
rep(i, 1, m) cout << ans[i] << ' '; cout << '\n';
return 0;
}