题解:[USACO19DEC] Milk Visits S

题目传送门

强化版:[USACO19DEC] Milk Visits G

题意重述

给定一棵无根树,每次给出 \(a_i,b_i,c_i\),求 \(a_i\sim b_i\) 的路径上是否存在一个点的权值为 \(c_i\)

题意分析

首先这样一眼树链剖分,将一对多的非线性信息转化为线性信息后处理即可。

但是,本题还存在更简单的算法:倍增。

可以参考倍增 LCA,在从 \(u,v\) 跳到 \(\operatorname{lca}(u,v)\) 的过程中判断是否存在 \(c_i\) 即可。

具体而言,就是设 \(G[x][i],H[x][i]\) 表示 \(x\)\(x\)\(2^i\) 级祖先的路径上是否存在 GH

其实也可以参考[NOIP2013 提高组]货车运输

AC 代码

//#include<bits/stdc++.h>
#include<algorithm> 
#include<iostream>
#include<cstring>
#include<iomanip>
#include<cstdio>
#include<string>
#include<vector>
#include<cmath>
#include<ctime>
#include<deque>
#include<queue>
#include<stack>
#include<list>
using namespace std;
const int N=1e5,M=1e5;
struct edge{
	int v,r;
}a[2*(N-1)+1];
int n,m,h[N+1],d[N+1],lg[N+1],f[N+1][__lg(N+1)+1];
bool vg[N+1],vh[N+1],G[N+1][__lg(N+1)+1],H[N+1][__lg(N+1)+1];
void create(int u,int v){
	static int top;
	a[++top]={v,h[u]};
	h[u]=top;
}
void dfs(int x,int fx){
	f[x][0]=fx;
	G[x][0]=vg[x]||vg[fx];
	H[x][0]=vh[x]||vh[fx];
	d[x]=d[fx]+1;
	for(int i=h[x];i>0;i=a[i].r){
		if(a[i].v==fx)continue;
		dfs(a[i].v,x);
	}
}
void pre(){
	for(int i=1;i<=n;i++)lg[i]=lg[i>>1]+1;
	for(int i=1;i<=n;i++)lg[i]--;
	dfs(1,0);
	for(int i=1;i<=lg[n];i++){
		for(int x=1;x<=n;x++){
			f[x][i]=f[f[x][i-1]][i-1];
			G[x][i]=G[x][i-1]||G[f[x][i-1]][i-1];
			H[x][i]=H[x][i-1]||H[f[x][i-1]][i-1];
		}
	}
}
bool query(int u,int v,char ch){
	if(d[u]<d[v])swap(u,v);
	for(int i=lg[d[u]-d[v]];i>=0;i--){
		if(d[f[u][i]]>=d[v]){
			switch(ch){
				case 'G':
					if(G[u][i])return true;
					break;
				case 'H':
					if(H[u][i])return true;
					break;
			}u=f[u][i];
		}
	}if(u==v){
		switch(ch){
			case 'G':
				if(vg[u]||vg[v])return true;
				break;
			case 'H':
				if(vh[u]||vh[v])return true;
				break;
		}return false;
	}
	for(int i=lg[d[u]];i>=0;i--){
		if(f[u][i]!=f[v][i]){
			switch(ch){
				case 'G':
					if(G[u][i]||G[v][i])return true;
					break;
				case 'H':
					if(H[u][i]||H[v][i])return true;
					break;
			}u=f[u][i],v=f[v][i];
		}
	}switch(ch){
		case 'G':
			if(G[u][0]||G[v][0])return true;
			break;
		case 'H':
			if(H[u][0]||H[v][0])return true;
			break;
	}return false;
}
int main(){
	/*freopen("test.in","r",stdin);
	freopen("test.out","w",stdout);*/
	
	scanf("%d %d",&n,&m);
	for(int i=1;i<=n;i++){
		char ch;
		cin>>ch;
		switch(ch){
			case 'G':vg[i]=true;break;
			case 'H':vh[i]=true;break;
		}
	}for(int i=1;i<n;i++){
		int u,v;
		scanf("%d %d",&u,&v);
		create(u,v);create(v,u);
	}pre();
	while(m--){
		int x,y;
		scanf("%d %d",&x,&y);
		char ch;
		cin>>ch;
		printf("%d",query(x,y,ch));
	}
	
	/*fclose(stdin);
	fclose(stdout);*/
	return 0;
}
posted @ 2025-07-20 14:20  TH911  阅读(4)  评论(0)    收藏  举报