题意:
N个点形成一棵树。给出根结点P还有树结构的信息。
输出每个点的F[i]。F[i]:以i为根的所有子结点中编号比i小的数的个数。
0<n<=10^5
思路:
方法一:直接DFS,进入结点x时记录一下比x小的数的个数。出来x时记录一下比x小的数的个数。相减就是F[x]。结合树状数组。
方法二:写下DFS序。对DFS序列建线段树。然后从小到大对结点进行插入。用线段树统计。
代码:(方法一)
int const N=1e5+5; int n,p; vector<int> G[N]; int C[N]; int ans[N]; stack<int> S; bool vis[N]; void Add(int x){ for(int i=x;i<=n;i+=lowbit(i)){ C[i]++; } } int query(int x){ int ret=0; for(int i=x;i>0;i-=lowbit(i)){ ret+=C[i]; } return ret; } void dfs(int u){ while(!S.empty()){ S.pop(); } mem(vis,false); S.push(u); vis[u]=true; while(!S.empty()){ int now=S.top(); int L=G[now].size(); bool flag=false; rep(i,0,L-1){ if(vis[G[now][i]]==false){ vis[G[now][i]]=true; flag=true; int t=G[now][i]; ans[t]=query(t-1); S.push(G[now][i]); break; } } if(!flag){ ans[now]=query(now-1)-ans[now]; Add(now); S.pop(); } } } int main(){ while(scanf("%d%d",&n,&p)!=EOF,n||p){ rep(i,1,n) G[i].clear(); mem(C,0); mem(ans,0); rep(i,1,n-1){ int a,b; scanf("%d%d",&a,&b); G[a].push_back(b); G[b].push_back(a); } dfs(p); rep(i,1,n-1) printf("%d ",ans[i]); cout<<ans[n]<<endl; } return 0; }