BuringStraw

BuringStraw

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

洛谷 | P4281 [AHOI2008] 紧急集合 / 聚會#

題目描述#

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

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

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

輸入輸出格式#

輸入格式:#

第一行兩個正整數 N 和 M(N<=500000,M<=500000),之間用一個空格隔開。分別表示等待點的個數(等待點也從 1 到 N 進行編號)和獲獎所需要完成集合的次數。 隨後有 N-1 行,每行用兩個正整數 A 和 B,之間用一個空格隔開,表示編號為 A 和編號為 B 的等待點之間有一條路。 接著還有 M 行,每行用三個正整數表示某次集合前小可可、小可可的朋友以及你所在等待點的編號。

輸出格式:#

一共有 M 行,每行兩個數 P,C,用一個空格隔開。其中第 i 行表示第 i 次集合點選擇在編號為 P 的等待點,集合總共的花費是 C 個遊戲幣。

輸入輸出樣例#

輸入樣例 #1:

6 4  
1 2  
2 3  
2 4 
4 5
5 6
4 5 6
6 3 1
2 4 4 
6 6 6

輸出樣例 #1:

5 2
2 5
4 1
6 0

說明#

提示:

40% 的數據中 N<=2000,M<=2000
100% 的數據中,N<=500000,M<=500000

這道題巨難!!

過程#

開始想的是求那三個點的 LCA,結果果然 WA 了。

左哥

~~ 同為不過樣例的代碼,怎麼我就一個點沒過呢(滑稽) ~~

後來看了 這個大佬 的題解,過程在原文,結論是:

那個點是 LCA (a,b),LCA (b,c),LCA (a,c) 中深度最大的

花費是 deep (a)+deep (b)+deep (c)? 最LCA 的深度?最LCA 的深度?2(其實就是減 a,b,c 三個深度,因為有兩個 LCA 是一樣的)

“在樹上任選三點 t1,t2,t3,LCA (t1,t2),LCA (t1,t3),LCA (t2,t3) 中一定有兩個是相等的。”

然後,在洛谷上過了,一中 oj 上 TLE 兩個點嘤。

最後用了快讀,加了 inline,都還過不了

Code#

(這份代碼沒用快讀)

#include<bits/stdc++.h>
using namespace std;

const int MAXN=500000*2+5;
int n,m;

struct tu{
	private:
		struct ed{
			int to,nex;
		} e[MAXN];
		int head[MAXN],newp,siz,root,H,f[MAXN][20];
		int depth[MAXN];
		bool bfsed;
		
	public:
		inline void clear(void){
			memset(e,0,sizeof(e));
			memset(head,0,sizeof(head));
			memset(f,0,sizeof(f));
			memset(depth,0,sizeof(depth));
			newp=0;
			siz=0;
			root=1;
			bfsed=0;
		}
		
		inline void vAdd(int p1,int p2){
			++newp;
			e[newp].to=p2;
			e[newp].nex=head[p1];
			head[p1]=newp;
		}
		
		inline void resize(int s){
			siz=s;
			H=(int)(1.0*log(siz)/log(2)+0.5);
		}
		
		inline int size(void){
			return siz;
		}
		
		inline int lca(int p1,int p2){
			if(!bfsed){
				bfs();
			}
			
			if(depth[p1]<depth[p2]){
				swap(p1,p2);
			}
			
			for(int i=H;i>=0;--i){
				if(depth[f[p1][i]]>=depth[p2]){
					p1=f[p1][i];
				}
			}
			
			if(p1==p2)return p1;
			
			for(int i=H;i>=0;--i){
				if(f[p1][i]!=f[p2][i]){
					p1=f[p1][i];
					p2=f[p2][i];
				}
			}
			return f[p1][0];
		}
		
		inline void solve(int x,int y,int z){
			int a,b,c;
			a=lca(x,y);
			b=lca(y,z);
			c=lca(x,z);
			int ans1,ans2;
			if(depth[a]>=depth[b] && depth[a]>=depth[c]){
				ans1=a;
			}
			
			else if(depth[b]>=depth[a] && depth[b]>=depth[c]){
				ans1=b;
			}
			
			else if(depth[c]>=depth[a] && depth[c]>=depth[b]){
				ans1=c;
			}
			int pt1=depth[x]-depth[a];
			int pt2=depth[y]-depth[b];
			int pt3=depth[z]-depth[c];
			ans2=pt1+pt2+pt3;
			printf("%d %d\n",ans1,ans2);
		}
		
		inline void bfs(void){
			queue<int> q;
			q.push(root);
			depth[root]=1;
			while(!q.empty()){
				int x=q.front();
				q.pop();
				for(int i=head[x];i;i=e[i].nex){
					int y=e[i].to;
					
					if(depth[y])continue;
					
					depth[y]=depth[x]+1;
					
					f[y][0]=x;
					
					for(int j=1;j<=H;++j){
						f[y][j]=f[f[y][j-1]][j-1];
					}
					
					q.push(y);
				}
			}
			bfsed=1;
		}
		
		
};

tu a;

int main(void){
	scanf("%d%d",&n,&m);
	a.clear();
	a.resize(n);
	for(int i=1;i<n;++i){
		int p1,p2;
		scanf("%d%d",&p1,&p2);
		a.vAdd(p1,p2);
		a.vAdd(p2,p1);
	}
	
	for(int i=1;i<=m;++i){
		int keke,kaka,waiwai;
		scanf("%d%d%d",&keke,&kaka,&waiwai);
		a.solve(keke,kaka,waiwai);
	}
	
	return 0;
}
載入中......
此文章數據所有權由區塊鏈加密技術和智能合約保障僅歸創作者所有。