Codeforces Round #430 (Div. 2) E. Nikita and game

来源:互联网 发布:java通过构造方法传参 编辑:程序博客网 时间:2024/05/21 05:18

Nikita plays a new computer game. There are m levels in this game. In the beginning of each level a new class appears in the game; this class is a child-class of the class yi (and yi is called parent-class for this new class). Thus, the classes form a tree. Initially there is only one class with index 1.

Changing the class to its neighbour (child-class or parent-class) in the tree costs 1 coin. You can not change the class back. The cost of changing the class a to the class b is equal to the total cost of class changes on the path from a to b in the class tree.

Suppose that at i -th level the maximum cost of changing one class to another is x. For each level output the number of classes such that for each of these classes there exists some other class y, and the distance from this class to y is exactly x.

Input
First line contains one integer number m — number of queries (1 ≤ m ≤ 3·105).

Next m lines contain description of queries. i -th line (1 ≤ i ≤ m) describes the i -th level and contains an integer yi — the index of the parent-class of class with index i + 1 (1 ≤ yi ≤ i).

Output
Suppose that at i -th level the maximum cost of changing one class to another is x. For each level output the number of classes such that for each of these classes there exists some other class y, and the distance from this class to y is exactly x.

Examples
input
4
1
1
2
1
output
2
2
2
3
input
4
1
1
2
3
output
2
2
2
2

题意是给出一个图,每次在树上某一个点后加一个点,构成新的树,问新的树有多少点可以作为树的直径,

直径的性质:从某一个点出发,这个树上离它的最远点必定是它直径的一端,从这些点出发,距离他们的最远点也是直径的一端,所以可以分成3种点,1:距离根最远的点;2:距离1类点最远的点;3:同时具有1类和2类性质的点;难处理的就是3类点,通过观察可以得出一个结论,如果直径发生变化,上一个图的第3类点不会成为第3类点;
然后做法就是建立两个set,分别存前两种点,第三类点存在第一类或第二类中,每次直径发生变化的时候,那么枚举它所在的那个set,如果有点到它的距离依然是最大距离,那么把它加到另一个set里。
因为只有第3类点会进入两次set,所以复杂度事nlogn。

#include<bits/stdc++.h>using namespace std;const int N = 3e5+100;int parent[25][N];int dep[N];int lca(int u,int v){    if(dep[u] > dep[v]) swap(u,v);    for(int k = 0;k <= 20;k ++){        if((dep[v]-dep[u])>>k&1){            v = parent[k][v];        }    }    if(u == v) return u;    for(int k = 20;k >= 0;k --){        if(parent[k][u] != parent[k][v]){            u = parent[k][u];            v = parent[k][v];        }    }    return parent[0][u];}void update(int v,int f){    parent[0][v] = f;    for(int i = 0;i <= 20;i ++){        if(parent[i][v] < 0) parent[i][v] = -1;        parent[i+1][v] = parent[i][parent[i][v]];    }}set<int> s1,s2;vector<int> v;int dis(int u,int v){    int f = lca(u,v);    return dep[v]+dep[u]-2*dep[f]+1;}int main(){    int n;    cin>> n;    update(1,-1);    dep[1] = 1;    bool tmp = true;    s1.insert(1);    int mx = 1;    for(int i = 1;i <= n;i ++){        int now;        scanf("%d",&now);        update(i+1,now);        dep[i+1] = dep[now]+1;        //int d1 = dep[bef]+dep[i+1]-2*dep[lca(i+1,bef)];        //int d2 = dep[befe]+dep[i+1]-2*dep[lca(i+1,befe)];        int d1 = s1.empty()?0:dis(i+1,*s1.begin());        int d2 = s2.empty()?0:dis(i+1,*s2.begin());        if(max(d1,d2)>mx){            mx = max(d1,d2);            if(mx == d1){                for(set<int>::iterator iter = s2.begin();iter != s2.end();iter ++){                    if(dis(*iter,i+1) == mx) s1.insert(*iter);                }                s2.clear();                s2.insert(i+1);            }            else{                for(set<int>::iterator iter = s1.begin();iter != s1.end();iter ++){                    if(dis(*iter,i+1) == mx) s2.insert(*iter);                }                s1.clear();                s1.insert(i+1);            }        }        else if(max(d1,d2) == mx){            if(d1 == mx){                s2.insert(i+1);            }            else s1.insert(i+1);        }        printf("%d\n",s1.size()+s2.size());    }    return 0;}
阅读全文
0 0
原创粉丝点击