ABC298Ex(2)
多次询问
,求 。
不失一般性的令
考虑
如果按照每个点到达
对其进行染色,则每种颜色都只有一个联通块,换句话说,颜色是树的一个划分。
考虑
但是如果
因此答案就是
此时式子已经相较于一开始变得更好处理,只需要求出一棵子树的所有点到子树内某点的距离和即可。即
对
其中
充分发挥人类智慧,改写为
发现路径上的点满足
注意,如果
如果令
时间复杂度
#include <bits/stdc++.h> #define int long long #define debug(...) fprintf(stderr,##__VA_ARGS__) bool Mbe; const int inf=1e18; const int maxn=2e5+10; std::vector<int>a[maxn]; int t[maxn],dep[maxn],s[maxn],f[maxn][20],lg[maxn],n,q,h[maxn]; template<typename T,typename I> void chkmin(T &a,I b){ a=std::min(a,b); } template<typename T,typename I> void chkmax(T &a,I b){ a=std::max(a,b); } namespace ST{ void dfs(int p,int fa){ f[p][0]=fa,dep[p]=dep[fa]+1; s[p]=1; h[p]=dep[p]; for(int i:a[p]){ if(i==fa) continue; dfs(i,p); s[p]+=s[i]; h[p]+=h[i]; } // t[p]=t[fa]+s[p]; } void dfs2(int p,int fa){ t[p]=t[fa]+s[p]; for(int i:a[p]){ if(i==fa) continue; dfs2(i,p); } } void init(int rt){ dfs(rt,rt); dfs2(rt,rt); lg[0]=-1; for(int i=1;i<=n;i++) lg[i]=lg[i>>1]+1; for(int j=1;j<20;j++) for(int i=1;i<=n;i++) f[i][j]=f[f[i][j-1]][j-1]; } int kth(int p,int k){ for(int i=19;i>=0;i--) if(k>=(1ll<<i)) k-=(1ll<<i),p=f[p][i]; return p; } int lca(int x,int y){ if(dep[x]<dep[y]) std::swap(x,y); for(int i=19;i>=0;i--) if(dep[f[x][i]]>=dep[y]) x=f[x][i]; if(x==y) return x; for(int i=19;i>=0;i--) if(f[x][i]!=f[y][i]) x=f[x][i],y=f[y][i]; return f[x][0]; } int dis(int x,int y){ return dep[x]+dep[y]-dep[lca(x,y)]*2; } int query(int x,int p){//求出 x 子树中的所有点到 p 的距离和 int res=s[x]*(dep[x]-1)+t[p]-t[x]; // debug("qwq res=%lld x=%lld p=%lld\n",res,x,p); if(lca(x,p)!=x) res=(dep[x]-1)*s[x]; res=h[x]-s[x]+s[x]*dis(1,(lca(x,p)==x?p:x))-2*res; if(lca(x,p)!=x) res+=s[x]*dis(p,x); // debug("res=%lld x=%lld h%lld s=%lld lca=%lld\n",res,x,h[x],s[x],lca(x,p)); return res; } } void check_s_t(){ debug("checking\n"); for(int i=1;i<=n;i++) debug("i=%lld s=%lld t=%lld h=%lld\n",i,s[i],t[i],h[i]); } bool Men; signed main(){ debug("%.8f\n",((&Men-&Mbe)/1048576.0)); std::cin>>n; for(int i=1;i<n;i++){ int u,v; std::cin>>u>>v; a[u].push_back(v),a[v].push_back(u); } ST::init(1); // debug("check:%lld\n",ST::query(4,1)); // check_s_t(); std::cin>>q; while(q--){ int x,y; std::cin>>x>>y; if(dep[x]<dep[y]) std::swap(x,y); int k=ST::lca(x,y);//x y 的 lca // debug("k=%lld\n",k); int m=ST::dis(x,y)/2;//阈值 int _x=ST::kth(x,m);//树上阈值级祖先 // debug("lca=%lld 阈值=%lld kth=%lld Q1=%lld Q2=%lld Q3=%lld 大家觉得呢:%lld\n",k,m,_x,ST::query(_x,x),ST::query(1,y),ST::query(_x,y),114); int ans=inf; if(_x==k) _x=ST::kth(x,m-1); chkmin(ans,ST::query(_x,x)+ST::query(1,y)-ST::query(_x,y)); // chkmin(ans,ST::query(_x,x)+ST::query(1,y)-2*ST::query(_x,y)); // if(ST::dis(x,y)&1) _x=f[_x][0],chkmin(ans,ST::query(_x,x)+ST::query(1,y)-2*ST::query(_x,y)); std::cout<<ans<<"\n"; } // debug("%.11lfms %.8f\n",clock(),(clock()/CLOCKS_PER_SEC)*1e3); } /* North London forever */
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!