【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\n",far[0]);
144     return 0;
145 }
奇妙代码

 

  

 

posted @ 2017-08-14 19:17  RogerDTZ  阅读(257)  评论(3编辑  收藏  举报