• codeforces 379F-New Year Tree


    传送门:QAQQAQ

    题意:原始有一棵根为1,有三个叶子2,3,4的树。有n个操作,每次可以在一个叶子下面续上两个节点,每次操作完问当前树的直径。

    思路:先预处理出树的直径,以及其中一条直径两端的点l,r,对于新加的点,只需计算其与两端的距离(倍增LCA),若大于ans,则更新直径l或r,否则就不变

    证明:假设加上点x后直径长为ans+1,因为x仅有一条边连它的父亲f,所以从f出发最远点距离为ans,即没加上点x前f为其中一条直径的端点。

               因为各个直径两两相交(否则定可以在上方找到一条把两直径连起来,使直径更长),两直径前后两端不同区间一样长,所以从f出发到l,r定有一个距离为ans,所以这样的更新是没有反例的

    补:树的直径dfs方法证明

    1    设u为s-t路径上的一点,结论显然成立,否则设搜到的最远点为T(往下走)则

    dis(u,T) >dis(u,s)     且  dis(u,T)>dis(u,t)   则最长路不是s-t了,与假设矛盾

    2   设u不为s-t路径上的点

        首先明确,假如u走到了s-t路径上的一点,那么接下来的路径肯定都在s-t上了,而且终点为s或t,在1中已经证明过了

        所以现在又有两种情况了:

        1:u走到了s-t路径上的某点,假设为X,最后肯定走到某个端点,假设是t ,则路径总长度为dis(u,X)+dis(X,t)

        2:u走到最远点的路径u-T与s-t无交点,则dis(u,T) >dis(u,X)+dis(X,t);显然,如果这个式子成立,

        则dis(s,X)+dis(X,u)+dis(u,T)>dis(s,X)+dis(X,t)=dis(s,t)  即dis(s,T)>dis(s,t) 最长路不是s-t矛盾    (摘自https://blog.csdn.net/frankax/article/details/79514778)

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 typedef long long ll;
     4 const int inf=(int)(2e9);
     5 const ll INF=(ll)(5e18);
     6 const int N=1000010;//pay attention to the size of the array!!!
     7 const int M=30;
     8 
     9 int n,l,r,num,ans;
    10 int father[N][30],d[N];
    11 vector<int> v[N];
    12 
    13 void add_edge(int x,int y)
    14 {
    15     v[x].push_back(y);
    16     father[y][0]=x;
    17     for(int i=1;i<M;i++) father[y][i]=father[father[y][i-1]][i-1];
    18     d[y]=d[x]+1;
    19 }
    20 
    21 void init()
    22 {
    23     num=5;
    24     memset(father,0,sizeof(father));
    25     for(int i=0;i<M;i++) father[1][i]=1;
    26     d[1]=0; d[2]=d[3]=d[4]=1;
    27 }
    28 
    29 int LCA(int x,int y)
    30 {
    31     if(d[x]<d[y]) swap(x,y);
    32     int dst=d[x]-d[y];
    33     for(int i=M-1;i>=0;i--)
    34     {
    35         int tmp=(1<<i);
    36         if(tmp<=dst)
    37         {
    38             dst-=tmp;
    39             x=father[x][i];
    40         }
    41     }
    42     for(int i=M-1;i>=0;i--)
    43     {
    44         if(father[x][i]==father[y][i]) continue;
    45         x=father[x][i]; y=father[y][i];
    46     }
    47     return father[x][0];
    48 }
    49 
    50 int dis(int x,int y)
    51 {
    52     if(x==y) return 0;
    53     int f=LCA(x,y);
    54     return d[x]+d[y]-d[f]*2;
    55 }
    56 
    57 void solve(int x)
    58 {
    59     if(dis(x,l)>ans)
    60     {
    61         ans=dis(x,l);
    62         r=x;//don't confuse the order of l&r
    63     }
    64     if(dis(x,r)>ans) 
    65     {
    66         ans=dis(x,r);
    67         l=x;
    68     }
    69 }
    70 
    71 int main()
    72 {
    73     scanf("%d",&n);
    74     init();
    75     for(int i=2;i<=4;i++)
    76     {
    77         add_edge(1,i);
    78     }
    79     l=2,r=4,ans=2;
    80     while(n--)
    81     {
    82         int x;
    83         scanf("%d",&x);
    84         add_edge(x,num);
    85         add_edge(x,num+1); 
    86         solve(num); 
    87         num+=2;
    88         printf("%d
    ",ans);
    89     }
    90     return 0;
    91 }
    View Code
  • 相关阅读:
    C++ 引用详解
    QT的UDP组播技术
    idea快捷键
    window10安装不同版本的mysql(5.7和8.0.25)
    第2篇scrum
    结对项目:四则运算(C语言)
    个人项目wc(C语言)
    修改博客园背景,css
    第一次作业
    第4篇 Scrum 冲刺博客(专✌️团队)
  • 原文地址:https://www.cnblogs.com/Forever-666/p/10660239.html
Copyright © 2020-2023  润新知