[省选联考 2021]宝石

宝石

题解

很水的一道题

首先可以考虑将询问 ( s , t ) (s,t) (s,t)拆成 ( s , l c a ( s , t ) ) (s,lca(s,t)) (s,lca(s,t)) ( l c a ( s , t ) , t ) (lca(s,t),t) (lca(s,t),t)两部分,离线下来处理。
由于在序列 P P P中,每种颜色都是唯一的,所以每个节点能在答案序列中所处的位置也是唯一的。
我们可以先用倍增的方式更新出来点 s s s在序列中向前/向后走多少步时能够到达哪个节点。
但由于开始开始节点不一定是节点 s s s,所以我们要离线下来记录下距当前点最近的某种颜色的点的位置,就像序列自动机那样,当然只需要存储当前这个点的状态了。
然后我们可以二分从这个点可以向上走多少步不超过lca,其实可以不用二分的,直接从高位开始枚举的

然后我们接着处理 ( l c a ( s , t ) , t ) (lca(s,t),t) (lca(s,t),t)的部分,我们既然已经知道了前一部分的答案,我们可以二分着个部分的答案,再判断点 t t t从答案开始,能否走完这部分新加的部分且不超过lca
这样就可以 O ( l o g 2 n ) O\left(log^2n\right) O(log2n)解决这两个部分了。

总时间复杂度 O ( n l o g 2 n ) O\left(nlog^2n\right) O(nlog2n)

题解

#include<cstdio>
#include<cmath>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<vector>
#include<queue>
#include<set>
#include<map>
#include<time.h>
using namespace std;
#define MAXN 200005
#define lowbit(x) (x&-x)
#define reg register
#define mkpr make_pair
#define fir first
#define sec second
typedef long long LL;
typedef unsigned long long uLL;
typedef unsigned int uint;
typedef pair<int,int> pii;
const int INF=0x7f7f7f7f;
const double PI=acos(-1.0);
template<typename _T>
_T Fabs(_T x){return x<0?-x:x;}
template<typename _T>
void read(_T &x){
	_T f=1;x=0;char s=getchar();
	while(s>'9'||s<'0'){if(s=='-')f=-1;s=getchar();}
	while('0'<=s&&s<='9'){x=(x<<3)+(x<<1)+(s^48);s=getchar();}
	x*=f;
}
int n,q,m,c,head[MAXN],tot,P[MAXN],col[MAXN],ltp[MAXN],dep[MAXN],L[MAXN],R[MAXN];
int father[MAXN],dfn[MAXN],pre[MAXN],idx,wson[MAXN],siz[MAXN],sta[MAXN],stak;
int pcol[MAXN][22],ncol[MAXN][22],icol[MAXN],hcol[MAXN],ans[MAXN];
vector<int>F[MAXN],T[MAXN];
struct edge{int to,nxt;}e[MAXN<<1];
struct ask{int s,t;}s[MAXN];
void addEdge(int u,int v){e[++tot]=(edge){v,head[u]};head[u]=tot;}
void dosaka1(int u,int fa){
	siz[u]=1;father[u]=fa;wson[u]=0;dep[u]=dep[fa]+1;
	for(int i=head[u];i;i=e[i].nxt){
		int v=e[i].to;if(v==fa)continue;
		dosaka1(v,u);siz[u]+=siz[v];
		if(siz[wson[u]]<siz[v])wson[u]=v;
	}
}
void dosaka2(int u,int tp){
	dfn[u]=++idx;ltp[u]=tp;pre[idx]=u;int las=hcol[col[u]];hcol[col[u]]=u;
	pcol[u][0]=hcol[P[icol[col[u]]-1]];ncol[u][0]=hcol[P[icol[col[u]]+1]];
	for(int i=1;i<21;i++)pcol[u][i]=pcol[pcol[u][i-1]][i-1],ncol[u][i]=ncol[ncol[u][i-1]][i-1];
	if(wson[u])dosaka2(wson[u],tp);
	for(int i=head[u];i;i=e[i].nxt)
		if(e[i].to!=wson[u]&&e[i].to!=father[u])
			dosaka2(e[i].to,e[i].to);
	hcol[col[u]]=las;
}
int lca(int a,int b){
	while(ltp[a]^ltp[b]){
		if(dep[ltp[a]]<dep[ltp[b]])swap(a,b);
		a=father[ltp[a]];
	}
	return dep[a]<dep[b]?a:b;
}
int FindPre(int u,int dp){for(int i=20;i>=0;i--)if(dp>>i&1)u=pcol[u][i];return u;}
int FindNxt(int u,int dp){for(int i=20;i>=0;i--)if(dp>>i&1)u=ncol[u][i];return u;}
void dosaka3(int u,int fa){
	int las=hcol[col[u]],siz=F[u].size();hcol[col[u]]=u;
	for(int i=0;i<siz;i++){
		int ti=F[u][i],v=s[ti].t,u_v=lca(u,v);int l=0,r=c;if(dep[hcol[P[1]]]<dep[u_v])continue; 
		while(l<r){int mid=l+r+1>>1;if(dep[u_v]>dep[FindNxt(hcol[P[1]],mid)])r=mid-1;else l=mid;}ans[ti]=l+1;
	}
	for(int i=head[u];i;i=e[i].nxt)if(e[i].to!=fa)dosaka3(e[i].to,u);hcol[col[u]]=las;
}
void dosaka4(int u,int fa){
	int las=hcol[col[u]],siz=T[u].size();hcol[col[u]]=u;
	for(int i=0;i<siz;i++){
		int ti=T[u][i],v=s[ti].s,u_v=lca(u,v);int l=0,r=c-ans[ti];if(dep[hcol[P[ans[ti]+1]]]<dep[u_v])continue;
		while(l<r){int mid=l+r+1>>1;if(dep[u_v]>dep[FindPre(hcol[P[ans[ti]+mid+1]],mid)])r=mid-1;else l=mid;}ans[ti]+=l+1;
	}
	for(int i=head[u];i;i=e[i].nxt)if(e[i].to!=fa)dosaka4(e[i].to,u);hcol[col[u]]=las;
}
signed main(){
	read(n);read(m);read(c);
	for(int i=1;i<=c;i++)read(P[i]),icol[P[i]]=i;
	for(int i=1;i<=n;i++)read(col[i]);
	for(int i=1,u,v;i<n;i++)read(u),read(v),addEdge(u,v),addEdge(v,u);
	dosaka1(1,0);dosaka2(1,1);read(q);
	for(int i=1;i<=q;i++)read(s[i].s),read(s[i].t),F[s[i].s].push_back(i),T[s[i].t].push_back(i);
	dosaka3(1,0);dosaka4(1,0);for(int i=1;i<=q;i++)printf("%d\n",ans[i]);
	return 0;
}

谢谢!!!

posted @   StaroForgin  阅读(8)  评论(0编辑  收藏  举报  
相关博文:
阅读排行:
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
点击右上角即可分享
微信分享提示