P4281 [AHOI2008]紧急集合 / 聚会

题目链接

题目:

给定一棵 n n n个结点的树,和 m m m次询问,每次询问给定 x , y , z x,y,z x,y,z,表示三个不同的结点,求结点 p p p满足 d = d i s ( x , p ) + d i s ( y , p ) + d i s ( z , p ) d=dis(x,p)+dis(y,p)+dis(z,p) d=dis(x,p)+dis(y,p)+dis(z,p)最小化,并输出 d d d
( 1 ≤ n ≤ 500000 , 1 ≤ x , y , z ≤ n ) (1 \le n \le 500000,1 \le x,y,z \le n) (1n500000,1x,y,zn)

题解:

一道分类讨论题。

  1. 存在 x , y x,y x,y满足 x x x y y y的祖先
    那么可能的情况有
    在这里插入图片描述

  2. 不存在 x , y x,y x,y满足 x x x y y y的祖先
    在这里插入图片描述
    由于 x , y , z x,y,z x,y,z是同等地位的,所以具有轮换性,我们可以用过适当的 s w a p swap swap将字母变成和上述两种情况相同来减少分类讨论的难度。
    由于点数比较大,用倍增 l c a lca lca的复杂度为 O ( ( n + m ) l o g n ) O((n+m)logn) O((n+m)logn),过不去,需要用ST表的 l c a lca lca

复杂度: O ( ( n l o g n + m ) O((nlogn+m) O((nlogn+m)
代码:
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<vector>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<string>
#include<bitset>
#include<sstream>
#include<ctime>
//#include<chrono>
//#include<random>
//#include<unordered_map>
using namespace std;


#define ll long long
#define ls o<<1
#define rs o<<1|1
#define pii pair<int,int>
#define fi first
#define se second
#define pb push_back
#define mp make_pair
#define sz(x) (int)(x).size()
#define all(x) (x).begin(),(x).end()
const double pi=acos(-1.0);
const double eps=1e-6;
const int mod=1e9+7;
const int INF=0x3f3f3f3f;
const int maxn=5e5+5;
ll read(){
	ll x=0,f=1;
	char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
	while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
	return x*f;
}
int tot,n,m,cnt;
int dep[maxn],ver[2*maxn],fir[maxn],st[maxn*2][21],logn[maxn*2];
struct edge{
	int to,nxt;
}es[maxn*2];
int head[maxn];
void init(){
	memset(head,-1,sizeof(head));
	tot=cnt=0;
	logn[0]=-1;
	for(int i=1;i<=2*n;i++)logn[i]=logn[i>>1]+1;
}
void addEdge(int u,int v){
	es[tot].to=v;
	es[tot].nxt=head[u];
	head[u]=tot++;
}
void dfs(int u,int fa,int d){
	dep[u]=d;
	ver[++cnt]=u;
	fir[u]=cnt;
	for(int i=head[u];i!=-1;i=es[i].nxt){
		int v=es[i].to;
		if(v==fa)continue;
		dfs(v,u,d+1);
		ver[++cnt]=u;
	}
}
void Init(){
	for(int i=1;i<=cnt;i++){
		st[i][0]=fir[ver[i]];
	}
	for(int j=1;(1<<j)<=cnt;j++){
		for(int i=1;i+(1<<j)-1<=cnt;i++){
			st[i][j]=min(st[i][j-1],st[i+(1<<(j-1))][j-1]);
		}
	}
}
int qry(int l,int r){
	int k=logn[r-l+1];
	return min(st[l][k],st[r-(1<<k)+1][k]);
}
int lca(int u,int v){
	int l=fir[u],r=fir[v];
	if(l>r)swap(l,r);
	return ver[qry(l,r)];
}
int ck(int a,int b,int c){
	int t1=lca(a,b),t2=lca(a,c),t3=lca(b,c),f=1;
	if(t1==a){
		;
	}
	else if(t1==b){
		swap(a,b);
	}
	else if(t2==a){
		swap(b,c);
	}
	else if(t2==c){
		swap(a,c);
		swap(b,c);
	}
	else if(t3==b){
		swap(a,b);
		swap(b,c);
	}
	else if(t3==c){
		swap(a,c);
	}
	else{
		f=0;
	}
	t1=lca(a,b),t2=lca(a,c),t3=lca(b,c);
	if(f){
		if(t2==c){
			return a;
		}
		else if(t2==a){
			if(t3==b){
				return b;
			}
			else{
				return t3;
			}
		}
		else{
			return a;
		}
	}
	else{
		if(t2==t3){
			return t1;
		}
		else{
			if(t1==t2){
				return t3;
			}
			else{
				return t2;
			}
		}
	}
} 
int dis(int u,int v){
	return dep[u]+dep[v]-2*dep[lca(u,v)];
}
int calc(int a,int b,int c,int u){
	// printf("%d %d %d\n",dis(a,u),dis(b,u),dis(c,u));
	return dis(a,u)+dis(b,u)+dis(c,u);
}
int main(void){
	// freopen("in.txt","r",stdin);
	n=read();m=read();
	init();
	int a,b;
	for(int i=1;i<=n-1;i++){
		a=read();b=read();
		addEdge(a,b);
		addEdge(b,a);
	}
	dfs(1,0,1);
	Init();
	int x,y,z;
	while(m--){
		x=read();y=read();z=read();
		int p=ck(x,y,z),d=calc(x,y,z,p);
		printf("%d %d\n",p,d);
	}
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
很抱歉,我似乎没有找到与彩旗飘飘Python相关的引用内容。但是,如果你想在Python中实现彩旗飘飘的效果,你可以使用Pygame库来创建动画。以下是一个简单的示例代码,可以帮助你开始: ```python import pygame import random # 初始化pygame pygame.init() # 设置屏幕尺寸 screen_width = 800 screen_height = 600 screen = pygame.display.set_mode((screen_width, screen_height)) pygame.display.set_caption("彩旗飘飘") # 加载彩旗图片 flag_image = pygame.image.load("flag.png") # 获取彩旗图片的宽度和高度 flag_width = flag_image.get_width() flag_height = flag_image.get_height() # 设置彩旗的起始位置 flag_x = screen_width // 2 - flag_width // 2 flag_y = screen_height // 2 - flag_height // 2 # 设置彩旗的速度 flag_speed_x = random.randint(-5, 5) flag_speed_y = random.randint(-5, 5) # 游戏主循环 running = True while running: for event in pygame.event.get(): if event.type == pygame.QUIT: running = False # 移动彩旗 flag_x += flag_speed_x flag_y += flag_speed_y # 如果彩旗碰到边界,反转速度方向 if flag_x <= 0 or flag_x + flag_width >= screen_width: flag_speed_x = -flag_speed_x if flag_y <= 0 or flag_y + flag_height >= screen_height: flag_speed_y = -flag_speed_y # 清空屏幕 screen.fill((255, 255, 255)) # 绘制彩旗 screen.blit(flag_image, (flag_x, flag_y)) # 更新屏幕 pygame.display.flip() # 退出游戏 pygame.quit() ``` 请注意,你需要将代码中的"flag.png"替换为你自己的彩旗图片。此外,你还可以根据需要调整彩旗的起始位置、速度等参数。希望这个示例代码能帮助到你!<span class="em">1</span><span class="em">2</span> #### 引用[.reference_title] - *1* [3d max制作彩旗飘飘](https://download.csdn.net/download/m0_71585230/88011500)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *2* [[Rqnoj-371][AHOI1997]彩旗飘飘](https://blog.csdn.net/w745241408/article/details/7176600)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值