题解 P4281 【[AHOI2008]紧急集合 / 聚会】

顾z

2018-10-11 21:23:48

Solution

# [顾](https://www.luogu.org/blog/RPdreamer/#)[z](https://www.cnblogs.com/-guz/) ~~你没有发现两个字里的blog都不一样嘛~~ qwq 题目描述-->[p4281 [AHOI2008]紧急集合 / 聚会](https://www.luogu.org/problemnew/show/P4281) 我天,这题恶心坏了. 话说没出样例就敢交题的我实在是tql。 ~w~ 明显到$LCA$处就能取到最小的值。 会需要求到$6$种(貌似可以求的更少. 首先这六种情况怎么算出来的. $$C_{3}^{2} \times 2 =6$$ > 其中$C_3^2$代表在三个点中,随便选两个点求$LCA$记作$X$。 > > 然后再求第三个点与$X$的$LCA$记作$Y$ 注意,这里要选择$X$作为集合点.这样会更优. 因为走到$Y$的话就会是两个点对花费的贡献.这样明显更大啊. 而走到$X$,这两个点对花费的贡献就会比较小了,另一个人多走就好了. 但是感觉不太对.但又的确是对的 emmm 比如这样:   ![](https://i.loli.net/2018/10/11/5bbf4d2d82cfc.png) 简单来看的话,我们求出了$b$和$c$的$LCA=X$ $a$和$X$的$LCA=Y$ 此时$a,b,c$走到$X$的价值为$4$,走到$Y$的价值为$5$ (这只是一个小栗子啦 qwq) ``代码`` ```c++ #include<cstdio> #include<cctype> #include<algorithm> #define R register #define N 500008 using namespace std; inline void in(int &x) { int f=1;x=0;char s=getchar(); while(!isdigit(s)){if(s=='-')f=-1;s=getchar();} while(isdigit(s)){x=x*10+s-'0';s=getchar();} x*=f; } int head[N],tot,depth[N],dis[N]; int n,m,gw[N][21],f[N][21]; struct cod{int u,v;}edge[N<<2]; inline void add(int x,int y,int z) { edge[++tot].u=head[x]; edge[tot].v=y; head[x]=tot; } void dfs(int u,int fa) { f[u][0]=fa;depth[u]=depth[fa]+1; dis[u]=dis[fa]+1; for(R int i=1;(1<<i)<=depth[u];i++) f[u][i]=f[f[u][i-1]][i-1]; for(R int i=head[u];i;i=edge[i].u) { if(edge[i].v==fa)continue; dfs(edge[i].v,u); } } inline int lca(int x,int y) { if(depth[x]>depth[y])swap(x,y); for(R int i=17;i>=0;i--) if(depth[x]+(1<<i)<=depth[y]) y=f[y][i]; if(x==y)return y; for(R int i=17;i>=0;i--) { if(f[x][i]==f[y][i])continue; x=f[x][i],y=f[y][i]; } return f[x][0]; } int main() { in(n),in(m); for(R int i=1,x,y;i<n;i++) in(x),in(y),add(x,y,1),add(y,x,1); dfs(1,0); for(R int i=1,x,y,z;i<=m;i++) { in(x),in(y),in(z); R int a=lca(x,y),b=lca(x,z),c=lca(y,z); R int aa=lca(a,z),bb=lca(y,b),cc=lca(x,c); R int father,res=214748364; int ansa=dis[x]+dis[y]-2*dis[a]+dis[a]-2*dis[aa]+dis[z]; int ansb=dis[x]+dis[z]-2*dis[b]+dis[b]-2*dis[bb]+dis[y]; int ansc=dis[y]+dis[z]-2*dis[c]+dis[c]-2*dis[cc]+dis[x]; if(res>ansa)res=ansa,father=a; if(res>ansb)res=ansb,father=b; if(res>ansc)res=ansc,father=c; printf("%d %d\n",father,res); } } ```