bzoj1787: [Ahoi2008]Meet 紧急集合&&bzoj1832: [AHOI2008]聚会

来源:互联网 发布:手机防盗警报器软件 编辑:程序博客网 时间:2024/05/29 17:29

传送门
三个节点两两做LCA。
除了两个相同的那另外一个就是答案。
为什么?显然成立呀
不懂自己画画图。
双倍经验最好了

#include<cmath>#include<cstdio>#include<cstring>#include<iostream>#include<algorithm>#define N 500005using namespace std;struct edge{int to,next;}e[N*2];int f[N][21],inn[N],out[N],dep[N],head[N];int tot,n,m,x,y,z,p,q,r,s,ans,tim;inline int read(){    int x=0;    char ch=getchar();    for (;ch<'0'||ch>'9';ch=getchar());    for (;ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-48;    return x;}inline void add(int x,int y){    e[++tot].to=y;    e[tot].next=head[x];    head[x]=tot;}void dfs(int fa,int x,int depth){    f[x][0]=fa;    dep[x]=depth;    inn[x]=++tim;    for (int i=head[x];i;i=e[i].next)        if (e[i].to!=fa) dfs(x,e[i].to,depth+1);    out[x]=++tim;}bool pd(int x,int y){return inn[x]<=inn[y]&&out[x]>=out[y];}int lca(int x,int y){    if (pd(x,y)) return x;    if (pd(y,x)) return y;    int k=x;    for (int j=20;j>=0;j--)        if (!pd(f[k][j],y)) k=f[k][j];    return f[k][0];}int main(){    n=read();    m=read();    for (int i=1;i<n;i++){        x=read();        y=read();        add(x,y);        add(y,x);    }    dfs(0,1,0);    f[1][0]=1;    for (int j=1;j<=20;j++)        for (int i=1;i<=n;i++) f[i][j]=f[f[i][j-1]][j-1];    for (int i=1;i<=m;i++){        x=read();        y=read();        z=read();        p=lca(x,y);        q=lca(x,z);        r=lca(y,z);        ans=dep[x]+dep[y]+dep[z];        if (p==q) ans-=2*dep[p]+dep[r],s=r;            else if (p==r) ans-=2*dep[p]+dep[q],s=q;                else ans-=2*dep[q]+dep[p],s=p;        printf("%d %d\n",s,ans);    }}