题面
题意
给出一棵有n个点的树,每条边有一个边权,对于 [ 0 , n − 1 ] [0,n-1] [0,n−1]的每一个数x求,至少删掉权值和为多少的边后,所有点的度数都小于等于x.
做法
首先考虑对于一个x怎么做,记
d
p
[
i
]
[
2
]
dp[i][2]
dp[i][2]表示第i个点与其父亲之间的边是否删去时,以i为根的子树最小要删去权值和为多少的点,转移时可以用堆处理出所有子节点t中
d
p
[
t
]
[
1
]
+
v
a
l
−
d
p
[
t
]
[
0
]
dp[t][1]+val-dp[t][0]
dp[t][1]+val−dp[t][0]最小的几个值,
v
a
l
val
val表示点
i
i
i与点
t
t
t之间的边的权值.
对于所有度数小于等于x的点来说,与它相连的所有边是否被删去,仅与边的另一头有关,因此可以将这条边的权值加入到另一头的堆中,然后在dp时只要考虑所有度数大于x的点即可,这样的总复杂度就是
∑
i
=
0
n
−
1
∑
j
=
1
n
[
d
s
[
j
]
>
i
]
=
∑
i
=
1
n
d
s
[
i
]
=
n
,
d
s
[
i
]
\sum_{i=0}^{n-1}\sum_{j=1}^n{[ds[j]>i]}=\sum_{i=1}^nds[i]=n,ds[i]
∑i=0n−1∑j=1n[ds[j]>i]=∑i=1nds[i]=n,ds[i]表示点
i
i
i的度数.
代码
#include<bits/stdc++.h>
#define ll long long
#define P pair<ll,ll>
#define mp make_pair
#define fi first
#define se second
#define N 250100
using namespace std;
ll n,md,sum,ans,ds[N],vis[N],nxt[N],dp[N][2];
struct Pq
{
ll size,sum;
priority_queue<ll>a,b;
void push(ll u){a.push(u),size++,sum+=u;}
void del(ll u){b.push(u),size--,sum-=u;}
void cle(){for(;!a.empty()&&!b.empty()&&a.top()==b.top();a.pop(),b.pop());}
void pop(){cle(),sum-=a.top(),a.pop(),size--;}
bool empty(){cle();return a.empty();}
ll top(){cle();return a.top();}
}pq[N];
vector<P>to[N];
vector<ll>have[N],use,gg;
inline bool cmp(P u,P v){return ds[u.fi]>ds[v.fi];}
inline void del(ll u)
{
ll i,t,p,q;
for(i=0;i<to[u].size();i++)
{
p=to[u][i].fi,q=to[u][i].se;
if(ds[p]<=md) break;
pq[p].push(q);
}
}
void dfs(ll now,ll last)
{
ll i,j,p,q,cnt=ds[now]-md,res=0;
vis[now]=md;
for(;pq[now].size>ds[now]-md;pq[now].pop());
for(i=0;i<to[now].size();i++)
{
p=to[now][i].fi;
if(ds[p]<=md) break;
if(p==last) continue;
dfs(p,now);
}
use.clear(),gg.clear();
for(i=0;i<to[now].size();i++)
{
p=to[now][i].fi,q=to[now][i].se;
if(ds[p]<=md) break;
if(p==last) continue;
ll t=dp[p][1]+q-dp[p][0];
if(t<0)
{
cnt--;
res+=dp[p][0]+t;
continue;
}
res+=dp[p][0];
pq[now].push(t);
use.push_back(t);
}
for(;!pq[now].empty()&&pq[now].size>cnt;pq[now].pop()) gg.push_back(pq[now].top());
dp[now][0]=res+pq[now].sum;
for(;!pq[now].empty()&&pq[now].size>cnt-1;pq[now].pop()) gg.push_back(pq[now].top());
dp[now][1]=res+pq[now].sum;
for(i=0;i<gg.size();i++) pq[now].push(gg[i]);
for(i=0;i<use.size();i++) pq[now].del(use[i]);
}
int main()
{
ll i,j,t,p,q,o;
cin>>n;
for(i=1;i<n;i++)
{
scanf("%lld%lld%lld",&p,&q,&o);
to[p].push_back(mp(q,o));
to[q].push_back(mp(p,o));
ds[p]++,ds[q]++,sum+=o;
}
for(i=1;i<=n;i++)
{
have[ds[i]].push_back(i);
sort(to[i].begin(),to[i].end(),cmp);
}
for(i=n;i>=1;i--)
{
if(have[i+1].size()) nxt[i]=i+1;
else nxt[i]=nxt[i+1];
}
cout<<sum<<" ";
for(md=1;md<n;md++)
{
ans=0;
for(i=0;i<have[md].size();i++) del(have[md][i]);
for(i=md+1;i;i=nxt[i])
{
for(j=0;j<have[i].size();j++)
{
t=have[i][j];
if(vis[t]==md) continue;
dfs(t,-1);
ans+=dp[t][0];
}
}
printf("%lld ",ans);
}
}