[省选联考 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;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通