• 【2016北京集训测试赛(八)】 直径 (虚树+树的直径)


    Description

      注意:时限更改为4s


    题解

      考虑最原始的直径求法:找到离根节点(或离其他任意一点)最远的节点far1,再从far1出发找到离far1最远的节点far2,far1至far2的距离即为直径。

      做完下面的优化就可以直接跑这个经典求法啦。


    复制的问题

      题目中提到了将原树的子树复制成新子树这一操作,显然如果我们将子树真正复制出来是会爆炸的。

      实际上我们可以将每棵新子树中,真正有用的节点提取出来,以简化每个子树的结构,再按照题目的要求连接各个新子树。

      我们用虚树来重构每一棵子树。每棵子树的虚树的关键点应至少包含:

    • 子树的根节点。
    • 这棵子树内部的直径的两端节点。
    • 题目所要求的,该子树要向其他子树连接的边的起点。

      子树内部的直径求法可以O(n)得到。对于一棵根节点为u的子树,它的直径要么在u的某个儿子v下面,要么由该树内来自不同子树的两个深度最大的节点组成。维护最大值和次大值,更新即可。


     编号问题  

      虚树重构时的重编号需要注意处理。。。这估计是这题最恶心的了。。。还有连子树边的操作也是。

      我们应该先对每棵子树进行重编号,再进行连子树边的操作。可以用map存储原节点对应的新编号,(实际上,对于某一个点,它在不同新子树中的新编号是不相同的)。

      在建立虚树的时候,不论是压栈还是弹栈都是对原来的节点进行操作,只不过连边的时候要连接它们的新编号。


      1 #include <bits/stdc++.h>
      2 using namespace std;
      3 typedef long long ll;
      4 const int N=300010,Bas=20;
      5 int n,m,tot,bas,ho[N],side[N][3],pre[N][Bas+1],dep[N];
      6 ll far[2];
      7 int timecnt,dfn[N],rt[N],cnt,newid[N],H[N*10];
      8 vector<int> use[N];
      9 map<int,int> tree[N];
     10 struct Edge{int v,w,next;}g[N*2+N*20];
     11 struct WaitEdge{
     12     int a,b,c,d;
     13     WaitEdge(){}
     14     WaitEdge(int aa,int bb,int cc,int dd){a=aa;b=bb;c=cc;d=dd;}
     15     void get(int &aa,int &bb,int &cc,int &dd){aa=a;bb=b;cc=c;dd=d;}
     16 }waitedge[N];
     17 struct MT{
     18     int a,as,b,bs;
     19     MT(){a=as=b=bs=-1;}
     20     void push(int c,int cs){
     21         if(c>a)
     22             b=a, bs=as,
     23             a=c, as=cs;
     24         else if(c>b)
     25             b=c, bs=cs;
     26     }
     27 }mt[N];
     28 inline void addEdge(int u,int v,int w,int *h){
     29     if(u==v) return;
     30     g[++tot].v=v; g[tot].w=w; g[tot].next=h[u]; h[u]=tot;
     31 }
     32 void preDfs(int u,int fa,int deep){
     33     dfn[u]=++timecnt;
     34     dep[u]=deep;
     35     pre[u][0]=fa;
     36     for(int i=1;i<=bas;i++) pre[u][i]=pre[pre[u][i-1]][i-1];
     37     for(int i=ho[u],v;i;i=g[i].next){
     38         if((v=g[i].v)!=fa){
     39             preDfs(v,u,deep+1);
     40             mt[u].push(mt[v].a+1,mt[v].as);
     41             if(side[v][0]&&side[v][0]>side[u][0])
     42                 side[u][0]=side[v][0],side[u][1]=side[v][1],side[u][2]=side[v][2];
     43         }
     44     }
     45     mt[u].push(0,u);
     46     if(mt[u].as!=-1&&mt[u].bs==-1){
     47         side[u][0]=1;
     48         side[u][1]=side[u][2]=u;
     49     }
     50     else
     51     if(mt[u].as&&mt[u].bs&&mt[u].a+mt[u].b+1>side[u][0]){
     52         side[u][0]=mt[u].a+mt[u].b+1;
     53         side[u][1]=mt[u].as;
     54         side[u][2]=mt[u].bs;
     55     }
     56 }
     57 int getLca(int a,int b){
     58     if(dep[a]<dep[b]) swap(a,b);
     59     for(int i=bas;i>=0;i--)
     60         if(dep[pre[a][i]]>=dep[b]) 
     61             a=pre[a][i];
     62     if(a==b) return a;
     63     for(int i=bas;i>=0;i--)
     64         if(pre[a][i]!=pre[b][i]) 
     65             a=pre[a][i], b=pre[b][i];
     66     return pre[a][0];
     67 }
     68 bool cmp(int x,int y){return dfn[x]<dfn[y];}
     69 int lis[N*10],K,st[N*10],top,tms[N*10];
     70 void build(int id){
     71     int u=rt[id],vsiz=use[id].size();
     72     K=3;
     73     lis[1]=u; lis[2]=side[u][1]; lis[3]=side[u][2];
     74     for(int i=0;i<vsiz;i++) lis[++K]=use[id][i];
     75     sort(lis+1,lis+1+K);
     76     K=unique(lis+1,lis+1+K)-lis-1;
     77     sort(lis+1,lis+1+K,cmp);
     78     for(int i=1;i<=K;i++) newid[lis[i]]=++cnt,tms[lis[i]]=id;
     79     if(K>1){
     80         st[1]=lis[1]; st[2]=lis[2];
     81         top=2;
     82         for(int i=3;i<=K;i++){
     83             int now=lis[i],lca=getLca(now,st[top]);
     84             while(1){
     85                 if(dep[lca]>=dep[st[top-1]]){
     86                     if(tms[lca]!=id) newid[lca]=++cnt,tms[lca]=id;
     87                     addEdge(newid[lca],newid[st[top]],dep[st[top]]-dep[lca],H);
     88                     addEdge(newid[st[top]],newid[lca],dep[st[top]]-dep[lca],H);
     89                     top--;
     90                     if(st[top]!=lca) st[++top]=lca;
     91                     break;
     92                 }
     93                 addEdge(newid[st[top-1]],newid[st[top]],dep[st[top]]-dep[st[top-1]],H);
     94                 addEdge(newid[st[top]],newid[st[top-1]],dep[st[top]]-dep[st[top-1]],H);
     95                 top--;
     96             }
     97             if(st[top]!=now)
     98                 st[++top]=now;
     99         }
    100         for(;top>1;top--){
    101             addEdge(newid[st[top]],newid[st[top-1]],dep[st[top]]-dep[st[top-1]],H);
    102             addEdge(newid[st[top-1]],newid[st[top]],dep[st[top]]-dep[st[top-1]],H);
    103         }
    104     }
    105     for(int i=1;i<=K;i++)
    106         tree[id][lis[i]]=newid[lis[i]];
    107 }
    108 void dfs(int u,int fa,ll dis){
    109     if(dis>far[0])
    110         far[0]=dis,
    111         far[1]=u;
    112     for(int i=H[u],v;i;i=g[i].next)
    113         if((v=g[i].v)!=fa)
    114             dfs(v,u,dis+g[i].w);
    115 }
    116 int main(){
    117     scanf("%d%d",&n,&m);
    118     bas=((int)log2(n))+1;
    119     for(int i=1,x,y;i<n;i++)
    120         scanf("%d%d",&x,&y),
    121         addEdge(x,y,1,ho),addEdge(y,x,1,ho);
    122     preDfs(1,0,1);
    123     for(int i=1,x;i<=m;i++)
    124         scanf("%d",&rt[i]);        
    125     for(int i=1,a,b,c,d;i<m;i++){    
    126         scanf("%d%d%d%d",&a,&b,&c,&d);
    127         waitedge[i]=WaitEdge(a,b,c,d);
    128         use[a].push_back(b); 
    129         use[c].push_back(d);
    130     }    
    131     for(int i=1;i<=m;i++)
    132         build(i);
    133     for(int i=1;i<m;i++){
    134         int a,b,c,d,x,y;
    135         waitedge[i].get(a,b,c,d);
    136         x=tree[a][b]; y=tree[c][d];
    137         addEdge(x,y,1,H); addEdge(y,x,1,H);
    138     }
    139     dfs(tree[1][rt[1]],0,1);
    140     int t=far[1];
    141     far[0]=far[1]=0;
    142     dfs(t,0,1);
    143     printf("%lld
    ",far[0]);
    144     return 0;
    145 }
    奇妙代码

      

  • 相关阅读:
    共轭梯度法
    OpenGLGLUT教程(十一) GLUT子菜单
    怎样让函数返回数组
    OpenGLGLUT教程(九) GLUT鼠标
    OpenGLGLUT教程(七) GLUT高级键盘控制
    OpenGLGLUT教程(六) GLUT场景漫游
    OpenGLGLUT教程(五) GLUT键盘控制
    OpenGLGLUT教程(八) GLUT场景漫游II
    dos指令 批处理文件
    新的启程!
  • 原文地址:https://www.cnblogs.com/RogerDTZ/p/7359731.html
Copyright © 2020-2023  润新知