1. 程式人生 > >Bzoj1787:[Ahoi2008]Meet 緊急集合

Bzoj1787:[Ahoi2008]Meet 緊急集合

進行 緊急集合 swa optimize brush har using light spa

技術分享 題意很明確 要求三個數的LCA 那麽該怎麽求呢? 初見時考慮的是去暴力求兩兩LCA 然後發現需要討論..思路混亂無奈去找了Hzwer的題解 此題有一個神奇的結論 三個數兩兩LCA必有兩個重復 那麽另外一個就是答案 技術分享 比如這張圖 設x,y,z是三個點 那麽顯然可以看出來,x和y與z的LCA都是點b
如果以b為答案 x和y都需要走一次ab 而以a為答案 只需要z走一次ab 那麽顯然a是更優的 於是每次去求出三點兩兩LCA,不同的即為問題1的答案 距離的話,因為我們記錄的距離數組都是距原點的 那麽比如上圖求dis(x,y),就只需要x的距離加上y的距離減去LCA的距離就是答案 於是只需要xyz三點分別與求出的答案進行dis操作即可
順便說一句 我再用cout我是()
#pragma GCC optimize("O2")
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<bitset>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<queue>
#include<stack>
#include<set>
#include<map>
#include<limits.h>
#include<ctime>
#define N 1000001
typedef long long ll;
const int inf=0x3fffffff;
const int maxn=2017;
using namespace std;
inline int read()
{
    int f=1,x=0;char ch=getchar();
    while(ch>‘9‘||ch<‘0‘)
    {
        if(ch==‘-‘)
        f=-1;
        ch=getchar();
    }
    while(ch<=‘9‘&&ch>=‘0‘)
    {
        x=(x<<3)+(x<<1)+ch-‘0‘;
        ch=getchar();
    }
    return f*x;
}
struct tsdl{
  int w,to,next;
} edge[N*4];
int head[N],tot,root=1;
void add(int ui,int vi)
{
  edge[tot].next=head[ui];
  edge[tot].to=vi;
  head[ui]=tot++;
}
int dep[N],dp[N][22],vis[N],n,m;
void dfs(int x)
{
  vis[x]=1;
  for(int i=1;i<=20;i++)
  {
    if(dep[x]<(1<<i))break;
    dp[x][i]=dp[dp[x][i-1]][i-1];
  }
  for(int i=head[x];i!=-1;i=edge[i].next)
  {
    int v=edge[i].to;
    if(vis[v])continue;
    dep[v]=dep[x]+1;
    dp[v][0]=x;
    dfs(v);
  }
}
int lca(int x,int y)
{
  if(dep[x]<dep[y])swap(x,y);
  int d=dep[x]-dep[y];
  for(int i=0;i<=18;i++)
  {
    if((1<<i)&d)
    x=dp[x][i];
  }
    if(x==y)return x;
    for(int i=20;i>=0;i--)
    {
      if(dp[x][i]!=dp[y][i])
      x=dp[x][i],y=dp[y][i];
    }
    if(x==y)return x;
    return dp[x][0];
}
int dis(int x,int y)
{
  int t=lca(x,y);
  return dep[x]+dep[y]-2*dep[t];
}
void cal(int x,int y,int z)
{
  int p1=lca(x,y),p2=lca(x,z),p3=lca(y,z);
  int tem;
  if(p1==p2)tem=p3;
  else if(p1==p3)tem=p2;
  else if(p2==p3)tem=p1;
  printf("%d %d\n",tem,dis(x,tem)+dis(tem,y)+dis(tem,z));
}
int main()
{
  memset(head,-1,sizeof(head));
  n=read(),m=read();
  for(int i=1;i<n;i++)
  {
    int x=read(),y=read();
    add(x,y);
    add(y,x);
  }
  dfs(1);
  for(int i=1;i<=m;i++)
  {
    int x=read(),y=read(),z=read();
    cal(x,y,z);
  }
}

Bzoj1787:[Ahoi2008]Meet 緊急集合