1. 程式人生 > 實用技巧 >洛谷 P4281 [AHOI2008]緊急集合 / 聚會

洛谷 P4281 [AHOI2008]緊急集合 / 聚會

洛谷 P4281 [AHOI2008]緊急集合 / 聚會

洛谷傳送門

題目描述

歡樂島上有個非常好玩的遊戲,叫做“緊急集合”。在島上分散有 nn 個等待點,有 n-1n−1 條道路連線著它們,每一條道路都連線某兩個等待點,且通過這些道路可以走遍所有的等待點,通過道路從一個點到另一個點要花費一個遊戲幣。

參加遊戲的人三人一組,開始的時候,所有人員均任意分散在各個等待點上(每個點同時允許多個人等待),每個人均帶有足夠多的遊戲幣(用於支付使用道路的花費)、地圖(標明等待點之間道路連線的情況)以及對話機(用於和同組的成員聯絡)。當集合號吹響後,每組成員之間迅速聯絡,瞭解到自己組所有成員所在的等待點後,迅速在 nn

個等待點中確定一個集結點,組內所有成員將在該集合點集合,集合所用花費最少的組將是遊戲的贏家。

小可可和他的朋友邀請你一起參加這個遊戲,由你來選擇集合點,聰明的你能夠完成這個任務,幫助小可可贏得遊戲嗎?

輸入格式

第一行兩個正整數 nn 和 mm,分別表示等待點的個數(等待點也從 11 到 nn 進行編號)和獲獎所需要完成集合的次數。

隨後 n-1n−1 行,每行兩個正整數 a,ba,b,表示編號為 aa 和編號為 bb 的等待點之間有一條路。

隨後 mm 行,每行用三個正整數 x,y,zx,y,z,表示某次集合前小可可、小可可的朋友以及你所在等待點的編號。

輸出格式

輸出共 mm 行,每行兩個用空格隔開的整數 p,cp

,c。其中第 ii 行表示第 ii 次集合點選擇在編號為 pp 的等待點,集合總共的花費是 cc 個遊戲幣。


題解:

題意很簡單。

那麼對於這三個點,首先我們要考慮它的集合點應該在哪。容易想到的是,肯定和LCA有關。

但是樣例會誤導我們,事實上,集合點的選擇應該符合:在這三個點兩兩搭配產生的三個LCA裡,深度最深的那個LCA

比較容易證明這個結論。

然後統計路徑長度的操作我們可以直接用深度來處理。

所以此題可切:

程式碼:

#include<cstdio>
#include<algorithm>
using namespace std;
const int maxn=5*1e5+10;
int n,m;
int tot,to[maxn<<1],nxt[maxn<<1],head[maxn];
int top[maxn],size[maxn],deep[maxn],fa[maxn],son[maxn];
void add(int x,int y)
{
    to[++tot]=y;
    nxt[tot]=head[x];
    head[x]=tot;
}
void dfs1(int x,int f)
{
    fa[x]=f;
    deep[x]=deep[f]+1;
    size[x]=1;
    for(int i=head[x];i;i=nxt[i])
    {
        int y=to[i];
        if(y==f)
            continue;
        dfs1(y,x);
        size[x]+=size[y];
        if(!son[x]||size[y]>size[son[x]])
            son[x]=y;
    }
}
void dfs2(int x,int t)
{
    top[x]=t;
    if(!son[x])
        return;
    dfs2(son[x],t);
    for(int i=head[x];i;i=nxt[i])
    {
        int y=to[i];
        if(y==fa[x]||y==son[x])
            continue;
        dfs2(y,y);
    }
}
int lca(int x,int y)
{
    while(top[x]!=top[y])
    {
        if(deep[top[x]]<deep[top[y]])
            swap(x,y);
        x=fa[top[x]];
    }
    if(deep[x]<deep[y])
        swap(x,y);
    return y;
}
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<n;i++)
    {
        int x,y;
        scanf("%d%d",&x,&y);
        add(x,y);
        add(y,x);
    }
    dfs1(1,0);
    dfs2(1,1);
    for(int i=1;i<=m;i++)
    {
        int a,b,c;
        int fsw,qyb,jzw,pos;
        scanf("%d%d%d",&a,&b,&c);
        int l1=lca(a,b),l2=lca(a,c),l3=lca(b,c);
        if(deep[l1]>=deep[l2]&&deep[l1]>=deep[l3])
            qyb=a,jzw=b,fsw=c,pos=l1;
        else if(deep[l2]>=deep[l1]&&deep[l2]>=deep[l3])
            qyb=a,jzw=c,fsw=b,pos=l2;
        else if(deep[l3]>=deep[l2]&&deep[l3]>=deep[l1])
            qyb=c,jzw=b,fsw=a,pos=l3;
        int l4=lca(qyb,fsw);
		int ans=deep[qyb]+deep[jzw]-2*deep[pos]+deep[fsw]+deep[pos]-2*deep[l4];
   		printf("%d %d\n",pos,ans);
    }
    return 0;
}