hihocoder1994 树与落叶 DFS+前缀和+二分
DFS找到节点删除的时间,删除的时间其实就是子树的最长链,然后给每个点打一个时间戳,然后求每个时间点对应删除的节点的个数,对于1-max_time时间戳求一个前缀和,然后二分找到和m距离最近的那一天
#include<iostream> #include<algorithm> #include<string.h> #include<stdio.h> #include<vector> #include<map> using namespace std; const int maxx = 2e5+6; const int INF = 0x3f3f3f3f; vector<int>v; int ver[maxx],edge[maxx],Next[maxx],head[maxx]; int sz[maxx]; int vis[maxx]; int cnt[maxx]; int pre[maxx]; int tot,n,mx,m; void add(int u,int v){ ver[++tot]=v;Next[tot]=head[u];head[u]=tot; ver[++tot]=u;Next[tot]=head[v];head[v]=tot; } int dfs(int u,int fa){ for (int i=head[u];i;i=Next[i]){ int v=ver[i]; if (v==fa)continue; vis[u]=max(vis[u],dfs(v,u)); } return vis[u]+1; } int main(){ int q; int uu,vv,st; scanf("%d%d",&n,&q); tot=0; for (int i=1;i<=n;i++){ scanf("%d",&uu); sz[uu]++; sz[i]++; if(uu==0){ st=i; continue; } add(uu,i); } for (int i=1;i<=n;i++){ if(sz[i]==1 && i!=st){ vis[i]=1; } } dfs(st,0); mx=0; for (int i=1;i<=n;i++){ cnt[vis[i]]++; mx=max(mx,vis[i]); } for (int i=1;i<=mx;i++){ pre[i]=pre[i-1]+cnt[i]; } pre[0]=0; v.push_back(n); for (int i=1;i<=mx;i++){ v.push_back(n-pre[i]); } reverse(v.begin(),v.end()); int ans; while(q--){ scanf("%d",&m); int pos=lower_bound(v.begin(),v.end(),m)-v.begin(); // cout<<"ss"<<pos<<endl; if (pos==v.size()){ printf("1\n"); }else if (pos==0){ printf("%d\n",v.size()); }else{ if (abs(v[pos]-m)<=abs(v[pos-1]-m)){ printf("%d\n",v.size()-pos); }else { printf("%d\n",v.size()-pos+1); } } } return 0; }
有不懂欢迎咨询
QQ:1326487164(添加时记得备注)