方法:从根节点开始广搜,如果遇到了应该删除的点,就再广搜删掉它的子树并标记,然后统计一下被标记的个数就是答案,所谓技巧就是从根节点开始搜索的时候,如果遇到了某个节点的距离<0,就让它是0,0可以消除负数效应,让后面的点重新参与正常删除操作,这个方法的正确性不难证明,可以自己画一下图。而且还有比较方便的方法就是,记录不被删除的点,然后n-他们就可以了。
代码如下:
#include<iostream> #include<cstdio> #include<cstring> #include<vector> #include<queue> using namespace std; #define N 100010 #define INF 1e9 struct Node { int to,val; }; vector<Node> vt[N]; int a[N],n,vis[N],del[N],fa[N],mark[N]; queue<int> que; queue<int> q1; void Delete(int u) { int len,v,now; while(!q1.empty()) q1.pop(); q1.push(u); del[u] = 1; while(!q1.empty()) { now = q1.front(); q1.pop(); len = vt[now].size(); for(int i = 0; i < len; i++) { v = vt[now][i].to; if(!del[v] && fa[u] != v) { del[v] = 1; q1.push(v); } } } } void bfs(int s) { que.push(s); vis[s] = 0; int now,nxt,len,dis; while(!que.empty()) { now = que.front(); que.pop(); len = vt[now].size(); for(int i = 0; i < len; i++) { nxt = vt[now][i].to; dis = vt[now][i].val; fa[nxt] = now; if(vis[nxt] == INF) { vis[nxt] = vis[now] + dis; if(vis[nxt] < 0) vis[nxt] = 0; if(vis[nxt] > a[nxt]) { Delete(nxt); } else que.push(nxt); } } } } int main() { memset(del,0,sizeof(del)); scanf("%d",&n); for(int i = 1; i <= n; i++) { scanf("%d",&a[i]); vt[i].clear(); fa[i] = i; vis[i] = INF; } int b,wei; Node L,R; for(int i = 2; i <= n; i++) { scanf("%d%d",&b,&wei); R.to = b; R.val = wei; vt[i].push_back(R); L.to = i; L.val = wei; vt[b].push_back(L); } while(!que.empty()) que.pop(); bfs(1); int ans = 0; for(int i = 1; i <= n; i++) { if(del[i]) { ans++; } } printf("%d\n",ans); return 0; }