#include <bits/stdc++.h> #define int long long #de...
Creado el: 9 de julio de 2026
Respondido usando GPT-5.5 Thinking por Chat01
Creado el: 9 de julio de 2026
Respondido usando GPT-5.5 Thinking por Chat01
#include <bits/stdc++.h>
#define int long long
#define pb push_back
#define pii pair <int,int>
using namespace std; const int MAXN=500005; const int INF=1e18;
int n,pa[MAXN],dfn[MAXN],siz[MAXN],id[MAXN],idx; int f[MAXN],dis[MAXN],summ;
vector <int> v[MAXN];
vector <pii> w[MAXN];
int answu,answv; int minn=INF;
int answ[MAXN];
int tmp[MAXN];
int dfs(int x,int fa) { pa[x]=fa; int res=0; siz[x]=1;
for (int i=0;i<v[x].size();i++) {
int vto=v[x][i]; pii wto=w[x][i];
if (vto==fa) continue;
res+=dfs(vto,x)+wto.second;
siz[x]+=siz[vto];
dis[vto]=dis[x]+wto.first+wto.second;
} return res;
} void dfs2(int x,int fa) { dfn[x]=++idx; id[idx]=x;
for (int i=0;i<v[x].size();i++) {
int vto=v[x][i]; pii wto=w[x][i];
if (vto==fa) continue;
f[vto]=f[x]-wto.second+wto.first;
dfs2(vto,x);
}
} struct SGM{
struct Tree{
int l,r; int val,laz;
}tr[MAXN4];
void pushup(int p){tr[p].val=min(tr[p2].val,tr[p2+1].val);}
void pushdown(int p) {
if (tr[p].laz!=0) {
tr[p2].val+=tr[p].laz,tr[p2].laz+=tr[p].laz;
tr[p2+1].val+=tr[p].laz,tr[p2+1].laz+=tr[p].laz;
tr[p].laz=0;
}
}
void BuildSGM(int p,int l,int r) {
tr[p].l=l,tr[p].r=r;
if (l==r) {tr[p].val=f[id[l]]-dis[id[l]];return;}
int midd=(l+r)/2;
BuildSGM(p2,l,midd),BuildSGM(p2+1,midd+1,r);
pushup(p);
} void add(int p,int l,int r,int x) {
if (l<=tr[p].l&&tr[p].r<=r) {
tr[p].val+=x,tr[p].laz+=x;
return ;
} int midd=(tr[p].l+tr[p].r)/2; pushdown(p);
if (l<=midd) add(p2,l,r,x);
if (r>midd) add(p2+1,l,r,x);
pushup(p);
}int querymin(int p) {
if (tr[p].l==tr[p].r) return tr[p].l;
pushdown(p);
if (tr[p2].val==tr[p].val) return querymin(p2);
else return querymin(p2+1);
pushup(p);
}
}T; void dfs3(int x,int fa) {
T.add(1,dfn[x],dfn[x],INF);
if (minn>(f[x]+T.tr[1].val)/2) {
minn=(f[x]+T.tr[1].val)/2;
answu=x,answv=id[T.querymin(1)];
}
T.add(1,dfn[x],dfn[x],-INF);
for (int i=0;i<v[x].size();i++) {
int vto=v[x][i]; pii wto=w[x][i];
if (vto==fa) continue;
int vall=wto.first+wto.second;
T.add(1,1,n,vall);
T.add(1,dfn[vto],dfn[vto]+siz[vto]-1,-vall2);
dfs3(vto,x);
T.add(1,1,n,-vall);
T.add(1,dfn[vto],dfn[vto]+siz[vto]-1,vall2);
}
}
int diss[MAXN],dismax[MAXN],lson[MAXN],istop[MAXN];
vector <int> nv[MAXN],nw[MAXN];
void dfs4(int x,int fa,int ww) {diss[x]=diss[fa]+ww;
dismax[x]=diss[x];
for (int i=0;i<nv[x].size();i++) {
int vto=nv[x][i],wto=nw[x][i];
if (vto==fa) continue;
dfs4(vto,x,wto);
dismax[x]=max(dismax[vto],dismax[x]);
if (dismax[lson[x]]<dismax[vto]) lson[x]=vto;
}
for (int i=0;i<nv[x].size();i++) {
if (nv[x][i]!=lson[x]) istop[nv[x][i]]=1;
}
} priority_queue <int> q;
void doit() {
for (int i=1;i<=n;i++) {
int st=i; if (tmp[st]==1) st=n+1;
for (int j=0;j<v[i].size();j++) {
int vto=v[i][j],wto=w[i][j].first+w[i][j].second;
if (i<vto) {
int to=(tmp[vto]==1)?n+1:vto;
if (st!=to) {nv[st].pb(to),nv[to].pb(st);nw[st].pb(wto),nw[to].pb(wto);}
}
}
}
dfs4(n+1,0,0);
istop[n+1]=1;
for (int i=1;i<=n+1;i++) {
if (istop[i]) {
q.push(dismax[i]-diss[i]);
}
} for (int i=3;i<=n;i++) {
if (!q.empty()) {
int x=q.top(); q.pop();
answ[i]=answ[i-1]+x;
}else answ[i]=answ[i-1];
}
}
signed main() { freopen("in.txt","r",stdin);
cin>>n; for (int i=1;i<=n-1;i++) {
int uu,vv,aa,bb;cin>>uu>>vv>>aa>>bb;
v[uu].pb(vv),v[vv].pb(uu);
w[uu].pb({aa,bb}),w[vv].pb({bb,aa}); summ+=aa+bb;
} f[1]=dfs(1,0); dfs2(1,0);
answ[1]=INF;
for (int i=1;i<=n;i++) f[i]=summ-f[i],answ[1]=min(answ[1],f[i]);
T.BuildSGM(1,1,n);
for (int i=1;i<=n;i++) cout<<f[i]<<' ';
cout<<'\n';
for (int i=1;i<=n;i++) cout<<dis[i]<<' ';
cout<<'\n';
dfs3(1,0); answ[2]=minn; cout<<answu<<' '<<answv<<'\n'; int lstu=answu,lstv=answv;
while (answu!=0) tmp[answu]++,answu=pa[answu];
while (answv!=0) tmp[answv]++,answv=pa[answv];
for (int i=1;i<=n;i++) {
if (i==lstu||i==lstv) tmp[i]=1;
else {
if (tmp[i]==1) tmp[i]=1;
else tmp[i]=0;
}
} doit();
int Q; cin>>Q; for (int i=1;i<=Q;i++) {
int x; cin>>x;
cout<<answ[x]<<'\n';
}
return 0;
}DEBUG找错误
你这份代码里最可能导致答案错误的核心 bug 有 4 个,其中第 1、2 个是实质性逻辑错误。
dfs() 中 dis[vto] 赋值顺序错了你现在写的是:
cppres+=dfs(vto,x)+wto.second; siz[x]+=siz[vto]; dis[vto]=dis[x]+wto.first+wto.second;
问题是:dfs(vto, x) 执行时,vto 的 dis[vto] 还没有被赋值。
所以 vto 的子节点、孙子节点计算 dis 时会用到错误的 dis[vto]。
应改为:
cppint dfs(int x,int fa) { pa[x]=fa; int res=0; siz[x]=1; for (int i=0;i<v[x].size();i++) { int vto=v[x][i]; pii wto=w[x][i]; if (vto==fa) continue; dis[vto]=dis[x]+wto.first+wto.second; // 必须放在递归前 res+=dfs(vto,x)+wto.second; siz[x]+=siz[vto]; } return res; }
这是一个非常关键的 bug。
dfs4() 中把父节点也标成了 istop你现在写的是:
cppfor (int i=0;i<nv[x].size();i++) { if (nv[x][i]!=lson[x]) istop[nv[x][i]]=1; }
这里没有排除父节点 fa,所以遍历到非根节点时,会把父亲也标记为 istop,导致后面优先队列 q 里塞进很多错误链。
应改为:
cppfor (int i=0;i<nv[x].size();i++) { int vto=nv[x][i]; if (vto==fa) continue; if (vto!=lson[x]) istop[vto]=1; }
完整修正版:
cppvoid dfs4(int x,int fa,int ww) { diss[x]=diss[fa]+ww; dismax[x]=diss[x]; lson[x]=0; for (int i=0;i<nv[x].size();i++) { int vto=nv[x][i], wto=nw[x][i]; if (vto==fa) continue; dfs4(vto,x,wto); dismax[x]=max(dismax[x],dismax[vto]); if (lson[x]==0 || dismax[lson[x]]<dismax[vto]) { lson[x]=vto; } } for (int i=0;i<nv[x].size();i++) { int vto=nv[x][i]; if (vto==fa) continue; if (vto!=lson[x]) istop[vto]=1; } }
answu 到 answv 路径的方式不严谨,会漏掉 LCA你现在的写法是:
cppwhile (answu!=0) tmp[answu]++,answu=pa[answu]; while (answv!=0) tmp[answv]++,answv=pa[answv]; for (int i=1;i<=n;i++) { if (i==lstu||i==lstv) tmp[i]=1; else { if (tmp[i]==1) tmp[i]=1; else tmp[i]=0; } }
这个逻辑相当于保留两条根路径的对称差部分,但如果 answu 和 answv 的 LCA 不是端点,那么 LCA 会被标记两次,即 tmp[lca]==2,最后会变成 0。
如果你的目的是把 answu 到 answv 的整条路径缩成一个点,那么 LCA 应该被保留。
建议直接改成这样:
cppint u=lstu, vv=lstv; static int mark[MAXN]; while (u) { mark[u]=1; u=pa[u]; } while (!mark[vv]) { tmp[vv]=1; vv=pa[vv]; } int lca=vv; tmp[lca]=1; u=lstu; while (u!=lca) { tmp[u]=1; u=pa[u]; }
这样 tmp[i]==1 才是真正表示节点 i 在 lstu 到 lstv 的路径上。
freopen 会导致提交 WA你的 main() 里有这些调试代码:
cppfreopen("in.txt","r",stdin);
以及:
cppfor (int i=1;i<=n;i++) cout<<f[i]<<' '; cout<<'\n'; for (int i=1;i<=n;i++) cout<<dis[i]<<' '; cout<<'\n'; cout<<answu<<' '<<answv<<'\n';
正式提交时必须删掉,否则输出格式一定错。
改成:
cppsigned main() { ios::sync_with_stdio(false); cin.tie(nullptr); cin>>n; ... }
dfscppint dfs(int x,int fa) { pa[x]=fa; int res=0; siz[x]=1; for (int i=0;i<v[x].size();i++) { int vto=v[x][i]; pii wto=w[x][i]; if (vto==fa) continue; dis[vto]=dis[x]+wto.first+wto.second; res+=dfs(vto,x)+wto.second; siz[x]+=siz[vto]; } return res; }
dfs4cppvoid dfs4(int x,int fa,int ww) { diss[x]=diss[fa]+ww; dismax[x]=diss[x]; lson[x]=0; for (int i=0;i<nv[x].size();i++) { int vto=nv[x][i],wto=nw[x][i]; if (vto==fa) continue; dfs4(vto,x,wto); dismax[x]=max(dismax[vto],dismax[x]); if (lson[x]==0 || dismax[lson[x]]<dismax[vto]) { lson[x]=vto; } } for (int i=0;i<nv[x].size();i++) { int vto=nv[x][i]; if (vto==fa) continue; if (vto!=lson[x]) istop[vto]=1; } }
把原来的:
cppwhile (answu!=0) tmp[answu]++,answu=pa[answu]; while (answv!=0) tmp[answv]++,answv=pa[answv]; for (int i=1;i<=n;i++) { if (i==lstu||i==lstv) tmp[i]=1; else { if (tmp[i]==1) tmp[i]=1; else tmp[i]=0; } }
换成:
cppstatic int mark[MAXN]; int u=lstu, vv=lstv; while (u) { mark[u]=1; u=pa[u]; } while (!mark[vv]) { tmp[vv]=1; vv=pa[vv]; } int lca=vv; tmp[lca]=1; u=lstu; while (u!=lca) { tmp[u]=1; u=pa[u]; }
你的 n 最大如果是 5e5,这些递归:
cppdfs dfs2 dfs3 dfs4
在链状树上可能会爆栈。
如果本地运行直接 RE,但逻辑没错,那大概率就是递归栈爆了。正式稳妥做法是改成非递归 DFS,或者在支持的环境里手动扩大栈。
优先改这四点:
**dfs 的 dis 赋值顺序、dfs4 排除父节点、路径标记包含 LCA、删除调试输出。**这几个不改,答案很容易整体偏掉。