青出于蓝胜于蓝 dfs+树状数组
武当派一共有 nn 人,门派内 nn 人按照武功高低进行排名,武功最高的人排名第 11,次高的人排名第 22,... 武功最低的人排名第 nn。现在我们用武功的排名来给每个人标号,除了祖师爷,每个人都有一个师父,每个人可能有多个徒弟。
我们知道,武当派人才辈出,连祖师爷的武功都只能排行到 pp。也就是说徒弟的武功是可能超过师父的,所谓的青出于蓝胜于蓝。
请你帮忙计算每个人的所有子弟(包括徒弟的徒弟,徒弟的徒弟的徒弟....)中,有多少人的武功超过了他自己。
输入格式
输入第一行两个整数 n, p $(1 \le n \le 100000, 1 \le p \le n)$。
接下来 n-1n−1 行,每行输入两个整数 u, v$(1 \le u, v \le n)$,表示 uu 和 vv 之间存在师徒关系。
输出格式
输出一行 nn 个整数,第 ii 个整数表示武功排行为 ii 的人的子弟有多少人超过了他。
行末不要输出多余的空格。
样例输入
10 5 5 3 5 8 3 4 3 1 2 1 6 7 8 7 9 8 8 10
样例输出
0 0 2 0 4 0 1 2 0 0
挺好的一个题,就记录下了。
算出每个点有多少个儿子节点,然后求相应的区间与l逆序对的数量。
1 #include <bits/stdc++.h> 2 #define lowbit(x) (-x&(x)) 3 using namespace std; 4 const int N = 1e5+10; 5 vector<int> vs[N]; 6 typedef pair<int,int> P; 7 vector<P> vs1[N]; 8 int a[N], d[N], sum[N], dp[N][2], res; 9 10 int dfs(int v, int f) { 11 a[++res] = v; 12 int sum = 0; 13 for(auto u : vs[v]) { 14 if(u == f) continue; 15 d[u] = dfs(u, v); 16 sum += d[u]+1; 17 } 18 return sum; 19 } 20 void add(int x, int y) { 21 while(x < N) { 22 sum[x] += y; 23 x += lowbit(x); 24 } 25 } 26 int query(int x) { 27 int s = 0; 28 while(x > 0) { 29 s += sum[x]; 30 x -= lowbit(x); 31 } 32 return s; 33 } 34 int main() { 35 int n, p, u, v; 36 scanf("%d%d", &n, &p); 37 for(int i = 1; i < n; i ++) { 38 scanf("%d%d", &u, &v); 39 vs[u].push_back(v); 40 vs[v].push_back(u); 41 } 42 d[p] = dfs(p, -1); 43 // for(int i = 1; i <= n; i ++) printf("%d ",a[i]);printf("\n"); 44 // for(int i = 1; i <= n; i ++) printf("%d ",d[a[i]]);printf("\n"); 45 for(int i = 1; i <= n; i ++) { 46 vs1[i+d[a[i]]].push_back(P(a[i],i)); 47 } 48 for(int i = n; i >= 1; i --) { 49 for(auto p : vs1[i]) { 50 dp[p.first][0] = query(p.first); 51 } 52 dp[a[i]][1] = query(a[i]); 53 // printf("%d\n",i); 54 add(a[i], 1); 55 } 56 for(int i = 1; i <= n; i ++) printf("%d%c",dp[i][1]-dp[i][0]," \n"[i==n]); 57 return 0; 58 }