2016北京集训测试赛直径
Posted RogerDTZ
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了2016北京集训测试赛直径相关的知识,希望对你有一定的参考价值。
注意:时限更改为4s
题解
考虑最原始的直径求法:找到离根节点(或离其他任意一点)最远的节点far1,再从far1出发找到离far1最远的节点far2,far1至far2的距离即为直径。
题目中提到了将原树的子树复制成新子树这一操作,显然如果我们将子树真正复制出来是会爆炸的。
实际上我们可以将每棵新子树中,真正有用的节点提取出来,以简化每个子树的结构,再按照题目的要求连接各个新子树。
我们用虚树来重构每一棵子树。每棵子树的虚树的关键点应至少包含:
- 子树的根节点。
- 这棵子树内部的直径的两端节点。
- 题目所要求的,该子树要向其他子树连接的边的起点。
子树内部的直径求法可以O(n)得到。对于一棵根节点为u的子树,它的直径要么在u的某个儿子v下面,要么由该树内来自不同子树的两个深度最大的节点组成。维护最大值和次大值,更新即可。
虚树重构时的重编号需要注意处理。。。这估计是这题最恶心的了。。。还有连子树边的操作也是。
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 }
以上是关于2016北京集训测试赛直径的主要内容,如果未能解决你的问题,请参考以下文章