[bzoj3572] [Hnoi2014]世界树
十分感人的一道题。。虚树+倍增。。
想了半天发现我竟然会写?而且似乎想对了。。。。然而细节打挂调了一个下午>_<
首先把虚树建出来,然后在虚树上跑两遍dfs求出每个点最接近的议事处与距离,再然后计算虚树上每一条边对答案的贡献。。
令mndis[x]表示点x离最近议事处的距离,mnpos[x]表示点x最近的议事处是哪个。
对于虚树上每条边i->j(i 是父亲),
计算贡献时要分两种情况:
1、mnpos[i]==mnpos[ j ]:这时候,原树上i 到 j 的那条链(不包括i 和j )及其孩子都归mnpos[i]管辖了。
我们可以先求出i 往 j 那个方向的第一个孩子记为next,
那么i-> j 这条边对mnpos[i]的贡献就是size[next]-size[ j ]。(size[x]表示原树里x子树里(包括x)点的个数)
2、mnpos[i]不等于mnpos[ j ]的时候,显然mnpos[i]不在 j 的子树里,而mnpos[ j ]在 j 的子树里。
现在i-> j 这条边会被分成两部分。。。我们只要找到分界点mid的位置就行了。。
两个议事处的距离dis等于mndis[i]+mndis[j]+( 边i-> j 的长度 ),
然后我们就知道mid是mnpos[ j ]往上数多少个祖先。这里似乎只能用倍增求mid= =
之后的计算就类似情况1了。
注意:到这时我们只计算了边的贡献,记得最后把没被考虑到的点要加上去;另外这题行末要有空格...吃了一发PE
1 #include<cstdio> 2 #include<iostream> 3 #include<cstring> 4 #include<algorithm> 5 using namespace std; 6 const int maxn=300023; 7 const int inf=1000233333; 8 struct zs{ 9 int too,pre; 10 }e[maxn<<1]; 11 struct zs1{ 12 int too,pre,dis; 13 }e1[maxn]; 14 int tot,tot1,last[maxn],last1[maxn]; 15 int size[maxn],dfn[maxn],bel[maxn],fa[maxn],sum[maxn],dep[maxn],next[maxn],tim; 16 int mndis[maxn],mnpos[maxn],id[maxn],sz[maxn]; 17 int st[maxn],top,poi[maxn],tmp[maxn]; 18 int FA[maxn][20],ans[maxn]; 19 int i,j,k,K,n,m,a; 20 21 int ra;char rx; 22 inline int read(){ 23 rx=getchar(),ra=0; 24 while(rx<'0'||rx>'9')rx=getchar(); 25 while(rx>='0'&&rx<='9')ra*=10,ra+=rx-48,rx=getchar();return ra; 26 } 27 28 29 inline void insert(int a,int b){ 30 e[++tot].too=b,e[tot].pre=last[a],last[a]=tot; 31 e[++tot].too=a,e[tot].pre=last[b],last[b]=tot; 32 } 33 inline void ins(int a,int b){ 34 // printf(" %d-->%d\n",a,b); 35 e1[++tot1].too=b,e1[tot1].dis=dep[b]-dep[a], 36 e1[tot1].pre=last1[a],last1[a]=tot1; 37 } 38 39 void dfs(int x){ 40 dep[x]=dep[fa[x]]+1,size[x]=1; 41 for(int i=1;i<=20&&(1<<i)<dep[x];i++) 42 FA[x][i]=FA[FA[x][i-1]][i-1]; 43 for(int i=last[x];i;i=e[i].pre)if(e[i].too!=fa[x]) 44 fa[e[i].too]=FA[e[i].too][0]=x,dfs(e[i].too),size[x]+=size[e[i].too]; 45 } 46 void dfs2(int x,int chain){ 47 int i,mxpos=0; 48 bel[x]=chain,dfn[x]=++tim; 49 if(dep[x]>2)sum[x]=sum[fa[x]]+size[fa[x]]-size[x]; 50 for(i=last[x];i;i=e[i].pre) 51 if(e[i].too!=fa[x]&&size[e[i].too]>=size[mxpos])mxpos=e[i].too; 52 if(!mxpos)return; 53 dfs2(mxpos,chain);next[x]=mxpos; 54 for(i=last[x];i;i=e[i].pre) 55 if(e[i].too!=fa[x]&&e[i].too!=mxpos)dfs2(e[i].too,e[i].too); 56 } 57 inline int getlca(int a,int b){ 58 if(dep[bel[a]]<dep[bel[b]])swap(a,b); 59 while(bel[a]!=bel[b]){ 60 a=fa[bel[a]]; 61 if(dep[bel[a]]<dep[bel[b]])swap(a,b); 62 } 63 return dep[a]<dep[b]?a:b; 64 } 65 inline int getnext(int f,int j){//找到f往j方向的第一个孩子 66 int pre=0; 67 while(bel[j]!=bel[f])pre=bel[j],j=fa[bel[j]]; 68 return j==f?pre:next[f]; 69 } 70 inline int getancestor(int x,int d){//找到x往上d 代祖先 71 for(register int i=19;i>=0;i--) 72 if((1<<i)&d)x=FA[x][i]; 73 return x; 74 } 75 76 void build(){ 77 int i,lca; 78 st[top=1]=poi[1]; 79 for(i=2;i<=K;i++){ 80 lca=getlca(poi[i],st[top]); 81 while(dfn[st[top]]>dfn[lca]) 82 if(dfn[st[--top]]<=dfn[lca]){ 83 ins(lca,st[top+1]); 84 if(lca!=st[top])st[++top]=lca; 85 }else ins(st[top],st[top+1]); 86 st[++top]=poi[i]; 87 } 88 while(top>1)top--,ins(st[top],st[top+1]); 89 } 90 void run1(int x){ 91 int tmpmn=id[x]==m?0:inf,tmppos=tmpmn==0?x:inf; 92 sz[x]=id[x]==m; 93 for(int i=last1[x];i;i=e1[i].pre){ 94 int to=e1[i].too; 95 run1(to);sz[x]+=sz[to]; 96 if( (mndis[to]+e1[i].dis<tmpmn) 97 ||(mndis[to]+e1[i].dis==tmpmn&&mnpos[to]<tmppos) ) 98 tmpmn=mndis[to]+e1[i].dis,tmppos=mnpos[to]; 99 } 100 mnpos[x]=tmppos,mndis[x]=tmpmn; 101 } 102 void run2(int x){ 103 ans[x]=0; 104 for(int i=last1[x],to=e1[i].too;i;to=e1[i=e1[i].pre].too){ 105 if( (e1[i].dis+mndis[x]<mndis[to]) 106 ||(e1[i].dis+mndis[x]==mndis[to]&&mnpos[x]<mnpos[to]) ) 107 mndis[to]=e1[i].dis+mndis[x],mnpos[to]=mnpos[x]; 108 run2(to); 109 } 110 } 111 void run3(int x){ 112 if(sz[x]==1){ans[x]+=size[x];last1[x]=0;return;} 113 int i,to,mid,next,j,k=mnpos[x],tmpsize=size[x]; 114 115 for(to=e1[i=last1[x]].too;i;to=e1[i=e1[i].pre].too){ 116 run3(to); 117 next=getnext(x,to),j=mnpos[to],tmpsize-=size[next]; 118 if(j==k)ans[j]+=size[next]-size[to]; 119 else 120 mid=(mndis[x]+e1[i].dis+mndis[to]), 121 mid=getancestor(j,(mid>>1)-(!(mid&1)&&k<j)), 122 ans[j]+=size[mid]-size[to],ans[k]+=size[next]-size[mid]; 123 } 124 ans[k]+=tmpsize,last1[x]=0; 125 } 126 127 bool cmp(int a,int b){return dfn[a]<dfn[b];} 128 int main(){ 129 n=read(); 130 for(i=1;i<n;i++)a=read(),insert(a,read()); 131 dfs(1);dfs2(1,1); 132 for(m=read();m;m--){ 133 K=read();tot1=0; 134 for(i=1;i<=K;i++)id[poi[i]=tmp[i]=read()]=m; 135 sort(poi+1,poi+1+K,cmp), 136 build(),run1(st[1]),run2(st[1]); 137 run3(st[1]);ans[mnpos[st[1]]]+=n-size[st[1]]; 138 for(i=1;i<=K;i++)printf("%d ",ans[tmp[i]]);puts(""); 139 if(m>1)for(i=1;i<=K;i++)ans[tmp[i]]=0; 140 } 141 142 return 0; 143 }
感人的是我把计算时的东西一次就考虑全了。。。结果多组数据..初始化写残吃了若干发RE..T_T,一开始没发现还写了非递归(反正都把dfn给搞出来了)>_<
中间手贱还CE了(掀桌。。
幸好我能用链剖的地方都用了链剖。。。刚好卡在#10.....