洛谷 P4281 [AHOI2008]緊急集合 / 聚會
阿新 • • 發佈:2020-10-20
洛谷 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
題解:
題意很簡單。
那麼對於這三個點,首先我們要考慮它的集合點應該在哪。容易想到的是,肯定和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; }