藍橋杯模擬賽 青出於藍而勝於藍
阿新 • • 發佈:2018-01-30
葉子 我們 樹狀數組 for def rip ear 空格 輸入
武當派一共有 nn 人,門派內 nn 人按照武功高低進行排名,武功最高的人排名第 11,次高的人排名第 22,... 武功最低的人排名第 nn。現在我們用武功的排名來給每個人標號,除了祖師爺,每個人都有一個師父,每個人可能有多個徒弟。
我們知道,武當派人才輩出,連祖師爺的武功都只能排行到 pp。也就是說徒弟的武功是可能超過師父的,所謂的青出於藍勝於藍。
請你幫忙計算每個人的所有子弟(包括徒弟的徒弟,徒弟的徒弟的徒弟....)中,有多少人的武功超過了他自己。
輸入格式
輸入第一行兩個整數 n, p(1 \le n \le 100000, 1 \le p \le n)n,p(1≤n≤100000,1≤p≤n)。
接下來 n-1n?1 行,每行輸入兩個整數 u, v(1 \le u, v \le n)u,v(1≤u,v≤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
dfs序列+樹狀數組
利用dfs序列把樹序列化,並可以用時間戳來維護一個非葉子節點的子樹。對於一個區間 求這個區間內比某個值要小的值的個數,利用權值線段樹的思想
代碼:
#include <cstdio> #include <cstring> #include <iostream> #include<vector> #include <queue> using namespace std; const int maxn=100010; int n,m; vector<int> edge[maxn]; int in[maxn*2],out[maxn*2]; int ret; int tree[maxn*2]; int lowbit(int t) { return t&(-t); } void up(int x,int y) { for(int i=x;i<=n;i+=lowbit(i)) tree[i]+=y; }int getsum(int x) { int ans=0; for(int i=x;i>0;i-=lowbit(i)) ans+=tree[i]; return ans; } void init() { memset(tree,0,sizeof(tree)); ret=0; for(int i=0;i<=n;i++) edge[i].clear(); } void dfs(int u,int fa) { in[u]=++ret; int len=edge[u].size(); for(int i=0;i<len;i++) { if(edge[u][i]!=fa) { dfs(edge[u][i],u); } } out[u]=ret; } int main() { scanf("%d %d",&n,&m); init(); for(int i=1;i<n;i++) { int x,y; scanf("%d %d",&x,&y); edge[x].push_back(y); edge[y].push_back(x); } dfs(m,m); for(int i=1;i<=n;i++) { cout<<getsum(out[i])-getsum(in[i]); if(i!=n) cout<<" "; up(in[i],1); } cout<<endl; return 0; }
藍橋杯模擬賽 青出於藍而勝於藍