CF2033G 题解
Descr
给你一棵 个点的有根树,根是 。
共有 次询问,每次询问形如 ,问从 开始往上走 步到达的点的的子树内距离 最远的点有多远。
。
Sol
首先 dfs 一遍,把每个点往下走到最深的点有多远,记为 。
考虑答案的式子,假设 向上走到 然后往下走到 的子树里最深的点,答案为 。
把贡献拆出来:。
但是这样做不对,有可能会出现 往上走到 再返回 往下走这样刷步数的情况。。。所以我们考虑把这种情况的影响消除。
一种解决方法比较聪明,记每个点的点权 为其父亲往下走除去 这个子树的 再减去父亲的 。查询直接树上倍增 步查最大值即可。
另一种是离线解法。。考虑把询问挂到点上,然后在树上再 dfs 一遍求出答案。建立一个线段树,dfs 进入一个点的时候求出跟上面类似的东西放到线段树下标 的位置,退出的时候清空。遇到一个询问就是线段树区间 。
Code
我的是离线做法。
#include <bits/stdc++.h>
using namespace std;
#define int long long
typedef pair<int,int> pii;
#define fi first
#define se second
#define pb push_back
#define mp make_pair
const int N=2e5+10,T=20,INF=0x3f3f3f3f3f3f3f3f,mod=1e9+7;
int n,q;
struct edge{
int v,nxt;
}e[N*2];
int head[N],cnt=2;
void add(int u,int v){
e[cnt].v=v;
e[cnt].nxt=head[u];
head[u]=cnt++;
}
int mxd[N],dep[N],L[N],R[N],ans[N];
vector<pii> qr[N];
void dfs(int u,int f){
dep[u]=dep[f]+1;
vector<int> son;
for(int i=head[u];i;i=e[i].nxt){
if(e[i].v!=f){
son.pb(e[i].v);
dfs(e[i].v,u);
mxd[u]=max(mxd[u],mxd[e[i].v]+1);
}
}
if(son.size()==1)L[son[0]]=R[son[0]]=-INF;
else if(son.size()>=2){
for(int i=1;i<son.size();i++)L[son[i]]=max(L[son[i-1]],mxd[son[i-1]]+1-dep[u]);
for(int i=son.size()-2;i>=0;i--)R[son[i]]=max(R[son[i+1]],mxd[son[i+1]]+1-dep[u]);
}
}
int t[N*4];
void update(int p,int l,int r,int pos,int val){
if(l==r){
t[p]=val;
return;
}
int m=(l+r)>>1;
if(pos<=m)update(p*2,l,m,pos,val);
else update(p*2+1,m+1,r,pos,val);
t[p]=max(t[p*2],t[p*2+1]);
}
int query(int p,int l,int r,int L,int R){
if(L<=l&&r<=R)return t[p];
int m=(l+r)>>1,ans=-INF;
if(L<=m)ans=max(ans,query(p*2,l,m,L,R));
if(R>m)ans=max(ans,query(p*2+1,m+1,r,L,R));
return ans;
}
void build(int p,int l,int r){
t[p]=-INF;
if(l==r)return;
int m=(l+r)>>1;
build(p*2,l,m);
build(p*2+1,m+1,r);
}
void dfs2(int u,int fa){
for(pii q:qr[u]){
ans[q.se]=max({mxd[u],dep[u]+query(1,1,n,max(1ll,dep[u]-q.fi),dep[u]),dep[u]-max(1ll,dep[u]-q.fi)});
}
for(int i=head[u];i;i=e[i].nxt){
if(e[i].v!=fa){
update(1,1,n,dep[u],max(L[e[i].v],R[e[i].v]));
dfs2(e[i].v,u);
}
}
update(1,1,n,dep[u],-INF);
}
void solve(){
cin>>n;
fill(L,L+n+10,-INF);
fill(R,R+n+10,-INF);
for(int i=1;i<n;i++){
int u,v;cin>>u>>v;
add(u,v),add(v,u);
}
dfs(1,1);
cin>>q;
for(int i=1;i<=q;i++){
int v,k;cin>>v>>k;
qr[v].pb(mp(k,i));
}
build(1,1,n);
dfs2(1,1);
for(int i=1;i<=q;i++)cout<<ans[i]<<' ';
cout<<'\n';
for(int i=1;i<=n;i++)qr[i].clear();
fill(head,head+n+10,0);
cnt=2;
fill(mxd,mxd+n+10,0);
fill(dep,dep+n+10,0);
fill(t,t+n*4+10,0);
fill(ans,ans+q+10,0);
}
signed main(){
ios::sync_with_stdio(false);
cin.tie(0),cout.tie(0);
int t;cin>>t;
while(t--)solve();
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】