题面:https://nanti.jisuanke.com/t/20690
用后序遍历可得到一个序列,问题就转为在(最左子节点...其他节点...根)这个区间中寻找比根小的节点树,再通过树状数组从小到大的顺序依次加入节点,维护区间和。
#include<cstdio> #include<cstdlib> #include<cstring> #include<string> #include<algorithm> #include<iostream> #include<queue> #include<map> #include<cmath> #include<set> #include<stack> #define ll long long #define pb push_back #define max(x,y) ((x)>(y)?(x):(y)) #define min(x,y) ((x)>(y)?(y):(x)) #define cls(name,x) memset(name,x,sizeof(name)) #define fs first #define sc second #define mp make_pair #define L(x) (1<<x) #define next Next #define index Index using namespace std; const int inf=1e9+10; const ll llinf=1e17+10; const int maxn=1e5+10; const int maxm=25e2+10; const int mod=1e9+7; int n,p; int index; int key[maxn]; vector<int> V[maxn]; int range[maxn]; int tree[maxn]; int dfs(int now,int fa) { int c=1; for(int i=0;i<V[now].size();i++) if(V[now][i]!=fa) { c+=dfs(V[now][i],now); } key[++index]=now; return range[now]=c; } int lowbit(int x){return x&(-x);} void TreeAdd(int pos,int val) { while(pos<=n) { tree[pos]+=val; pos+=lowbit(pos); } } int Treesum(int r) { int ans=0; while(r>0) { ans+=tree[r]; r=r-lowbit(r); } return ans; } int TreeQuery(int l,int r)//返回[l,r]总和 { return Treesum(r)-Treesum(l-1); } int main() { //freopen("in.txt","r",stdin); while(~scanf("%d %d",&n,&p)) { cls(tree,0); index=0; for(int i=1;i<=n-1;i++) { int u,v; scanf("%d %d",&u,&v); V[u].pb(v); V[v].pb(u); } dfs(p,-1); pair<int,int> point[maxn]; for(int i=1;i<=n;i++) point[i]=mp(key[i],i); sort(point+1,point+1+n); int ans[maxn]; for(int i=1;i<=n;i++) { int id=point[i].fs; int pos=point[i].sc; ans[id]=TreeQuery(pos+1-range[id],pos); TreeAdd(pos,1); //printf("[%d %d]",pos+1-range[id],pos); } for(int i=1;i<=n;i++) printf("%d%s",ans[i],i==n?" ":" "); } return 0; }