[湖南集训] 谁更厉害 题解
这道题似乎做法多得离谱,因为在学长链剖分,所以写一篇长链剖分题解。
容易发现假如 \(b\) 比 \(a\) 更加厉害,那么答案就是 \(\min(dep_a-1,k)\times(sz_a-1)\),考虑 \(a\) 比 \(b\) 更加厉害的情况。
我们设 \(f'_{u,i}\) 表示 \(\sum\limits_{v\in T(u)-\{u\},\operatorname{dis}(u,v)\le i}sz_v-1\),那么转移方程即为:
\[f'_{u,i}=\sum_{v\in SON(u)}f'_{v,i-1}+sz_v-1(i>1)
\]
\[f'_{u,i}=sz_u-|SON(u)|-1(i=1)
\]
由于第二维是深度维,所以可以用长链剖分优化至 \(O(n)\)。但是转移方程中的常数 \(sz_v-1\) 让人很难办。考虑打标记的 \(trick\)。我们设 \(tag_u=\sum\limits_{v\in T(u)-{u}}sz_v-1\),并将 \(f_{u,i}\) 定义为 \(f'_{u,i}-tag_u\),那么转移方程就变为:
\[\begin{aligned}
f_{u,i}&=-tag_v+\sum_{v\in SON(u)}f'_{v,i-1}+sz_v-1\\
&=\sum_{v\in SON(u)}f'_{v,i-1}+sz_v-1-tag_v-(sz_v-1)\\
&=\sum_{v\in SON(u)}f_{v,i-1}(i>1)\\
f_{u,i}&=sz_u-|SON(u)|-tag_u-1(i=1)
\end{aligned}\]
这样长链剖分就方便许多了,时间复杂度 \(O(n)\)。
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=3e5+5;
struct que{int x,id;};
int n,q,dep[N],sz[N],sn[N],tag[N];
int len[N],zjy[N],ans[N],*ed,*f[N];
vector<int>g[N];vector<que>qu[N];
void dfs(int x,int fa){
dep[x]=dep[fa]+1;
for(auto y:g[x]) if(y!=fa){
dfs(y,x),sz[x]+=sz[y];
if(len[x]<len[y]+1)
len[x]=len[y]+1,sn[x]=y;
}sz[x]++;
}void dp(int x,int fa){
if(sn[x]) f[sn[x]]=f[x]+1,dp(sn[x],x),tag[x]=tag[sn[x]]+sz[sn[x]]-1;
for(auto y:g[x]) if(y!=fa&&y!=sn[x]&&len[y]){
f[y]=ed,ed+=len[y],dp(y,x),tag[x]+=tag[y]+sz[y]-1;
for(int i=1;i<=len[y];i++) f[x][i+1]+=f[y][i];
}f[x][1]-=tag[x]-sz[x]+g[x].size()+(!fa);
for(auto c:qu[x])
ans[c.id]=(!len[x]?0:f[x][min(c.x,len[x])]+tag[x]+min(dep[x]-1,c.x)*(sz[x]-1));
}signed main(){
ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0),cin>>n>>q;
for(int i=1,u,v;i<n;i++)
cin>>u>>v,g[u].push_back(v),g[v].push_back(u);
for(int i=1,a,k;i<=q;i++) cin>>a>>k,qu[a].push_back({k,i});
dfs(1,0),f[1]=zjy,ed=zjy+len[1],dp(1,0);
for(int i=1;i<=q;i++) cout<<ans[i]<<"\n";
return 0;
}

浙公网安备 33010602011771号