题解:P17724 [SCP-S 2026] 路短最 / path
先考虑写个形式比较好的正确的暴力。
首先建圆方树。下面认为一次访问是从堆中取出这个点。
首先考察一个环上的点,在环上最靠近
考虑从上往下分析,这是因为想要更新
不妨设
不妨对结构稍加变化方便刻画,容易发现我们本质只在乎访问时的
考虑拆贡献,不妨将贡献拆到
不妨
使用哈希表,时间复杂度
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int maxn = 5e5+114;
vector<int> E[maxn];
int fa[maxn];
int n,m;
array<int,2> t[maxn];
int dfn[maxn],low[maxn],dfncnt;
int stk[maxn],tp;
void tarjan(int u){
dfn[u]=low[u]=++dfncnt;
stk[++tp]=u;
for(int v:E[u]){
if(dfn[v]==0){
tarjan(v);
low[u]=min(low[u],low[v]);
if(low[v]>=dfn[u]){
vector<int> seq;
while(stk[tp]!=v){
seq.push_back(stk[tp]);
tp--;
}
seq.push_back(v);
tp--;
if(seq.back()<seq[0]) reverse(seq.begin(),seq.end());
for(int x:seq) fa[x]=u;
for(int i=0;i<(int)seq.size();i++) t[seq[i]]={(i==(int)seq.size()-1?1:i+1),(int)seq.size()-i};
}
}else low[u]=min(low[u],dfn[v]);
}
}
vector<int> tr[maxn];
int sz[maxn];
int son[maxn];
void dfs(int u){
sz[u]=1;
for(int v:tr[u]){
dfs(v);
sz[u]+=sz[v];
if(sz[v]>sz[son[u]]) son[u]=v;
}
}
unordered_map<int,int> dp[maxn];
int tagv[maxn],tagi[maxn];
int tag[maxn];
int ans;
inline int get(int u,int i){
auto it=dp[u].find(i);
return it==dp[u].end()?0:it->second;
}
void DP(int u){
int mx=0;
for(int v:tr[u]) DP(v);
if(son[u]!=0){
int d=max(0*1ll,t[son[u]][0]-t[son[u]][1]);
int c=(d>0?get(son[u],d-tagi[son[u]])+tagv[son[u]]:0);
vector<int> f(d+1);
for(int i=1;i<=d;i++) f[i]=get(son[u],i-tagi[son[u]])+tagv[son[u]];
swap(dp[u],dp[son[u]]);
swap(tagv[u],tagv[son[u]]);
swap(tagi[u],tagi[son[u]]);
tagi[u]+=d;
for(int i=1;i<=d;i++){
dp[u][i-tagi[u]]=-tagv[u];
}
for(int i=1;i<=d;i++) dp[u][i-tagi[u]]+=f[i]-c;
tagv[u]+=(c+1);
for(int v:tr[u]){
if(v!=son[u]){
int c=get(v,sz[v]+1-tagi[v])+tagv[v];
tagv[v]-=c;
int d=max(0*1ll,t[v][0]-t[v][1]);
if(d==0){
tagv[u]+=c;
for(int i=1;i<=sz[v];i++){
dp[u][i-tagi[u]]+=get(v,i-tagi[v])+tagv[v];
}
}else{
int C=c+get(v,d-tagi[v])+tagv[v];
tagv[u]+=c+C;
mx=max(mx,d);
tag[d]-=C;
for(int i=1;i<=sz[v];i++){
int val=get(v,i-tagi[v])+tagv[v];
if(i<=d) dp[u][i-tagi[u]]+=val;
dp[u][i-tagi[u]+d]+=val;
}
}
}
}
}else tagv[u]++;
if(mx>0){
for(int i=mx;i>1;i--) tag[i-1]+=tag[i];
for(int i=1;i<=mx;i++) dp[u][i-tagi[u]]+=tag[i],tag[i]=0;
}
if(t[u][0]>t[u][1]) ans+=get(u,t[u][0]-t[u][1]-tagi[u])+tagv[u];
}
void work(){
cin>>n>>m;
for(int i=1;i<=m;i++){
int u,v;
cin>>u>>v;
E[u].push_back(v);
E[v].push_back(u);
}
tarjan(1);
for(int i=2;i<=n;i++) tr[fa[i]].push_back(i);
dfs(1);
ans=n;
DP(1);
cout<<ans<<"\n";
for(int i=0;i<=n;i++){
fa[i]=0;
sz[i]=son[i]=0;
E[i].clear();
tr[i].clear();
stk[i]=dfn[i]=low[i]=0;
t[i]={0,0};
dp[i].clear();
tagv[i]=tagi[i]=0;
}
tp=0;
dfncnt=0;
}
signed main(){
ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
int c,t;
cin>>c>>t;
while(t--) work();
return 0;
}