[codeforces contest 1119 F] Niyaz and Small Degrees 解题报告 (树形DP+堆)
interlinkage:
http://codeforces.com/contest/1119/problem/F
description:
有一颗$n$个节点的树,每条边有一个边权
对于一个$x$,删去一些边使得每个点的度数都不超过$x$,最小化删去边的边权并输出
需要一次输出$x=0->n-1$的值
$1<=n<=250000$
solution:
- part1
- 先考虑单个$x$的做法。任选一个根,设$f_{u,0/1}$表示以节点$u$为根的子树内,节点$u$与它的父亲不断/断的最小代价;
- 显然这个可以讨论转移,但我们换一个更好的角度;
- 设$v$为$u$的一个儿子,若$f_{v,1}+c<=f_{v,0}$,即断的话比不断更优秀的,那么我们一定选择断,因为这样还可以让$u$的度数小$1$。这种情况我们就直接加上$f_{v,1}+c$,并让$u$度数$--$;
- 否则的话我们就先假设这条边不断,加上$f_{v,0}$。那么到最后可能会发现$u$的度数不满足不超过$x$,显然我们要把若干个$f_{v,0}$变成$f_{v,1}+c$;
- 我们对每个点维护一个$f_{v,1}+c-f_{v,0}$的堆,取度数-$x$个最小的就好了;
- 这里的堆本质上维护的就是通过多大的代价能让度数减一;
- part2
- 现在考虑多个$x$,从小做到大
- 有一个很显然的想法,若是一个点原来的度数就不超过$x$,那么这个点可以直接删掉;
- 做法是把所有以这个点为端点的边放到这些边的另一个端点的堆里面,表示可以通过断掉这条边来使得度数减一;
- 剩下的就是对所有有用的点,即度数大于$x$的点做上面的$DP$就好了;
- part3
- 复杂度显然为$\sum_{x=0}^{n-1}\sum_{i=1}^{n}[du_i>x]=\sum_{i=1}^{n}du_i=O(n)$;
code:
#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<vector>
#include<queue>
#define fi first
#define se second
#define pb push_back
using namespace std;
typedef long long ll;
typedef pair<ll,ll> pll; const ll N=;
ll n;
ll du[N],nxt[N],vis[N];
ll sum[N];
vector <pll> e[N];
vector <ll> d[N];
inline ll read()
{
char ch=getchar();ll s=,f=;
while (ch<''||ch>'') {if (ch=='-') f=-;ch=getchar();}
while (ch>=''&&ch<='') {s=(s<<)+(s<<)+ch-'';ch=getchar();}
return s*f;
}
bool cmp(pll x,pll y) {return du[x.fi]<du[y.fi];}
struct node
{
priority_queue <ll> A,B;
void push(ll x) {A.push(x);}
void del(ll x) {B.push(x);}
ll top() {while (!B.empty()&&A.top()==B.top()) A.pop(),B.pop();return A.top();}
void pop() {top();A.pop();}
ll size() {return A.size()-B.size();}
}h[N];
void upd(ll x,ll num)
{
while (h[x].size()>num)
{
sum[x]=sum[x]-h[x].top();
h[x].pop();
}
}
void upd1(ll x,ll num,vector <ll> &add)
{
while (h[x].size()>num)
{
sum[x]=sum[x]-h[x].top();
add.pb(h[x].top());
h[x].pop();
}
}
void dele(ll x)
{
vis[x]=;
for (ll i=;i<e[x].size();i++)
{
ll y=e[x][i].fi,c=e[x][i].se;;
if (vis[y]) continue;
h[y].push(c);sum[y]=sum[y]+c;
}
}
ll D;
ll f[N][],st[N];
void dfs(ll x)
{
vis[x]=;ll num=du[x]-D;
upd(x,num);
vector <ll> add,del;
add.clear();del.clear();
ll siz=e[x].size(),tot=;
while (st[x]<siz&&du[e[x][st[x]].fi]<=D) st[x]++;
for (ll i=st[x];i<siz;i++)
{
ll y=e[x][i].fi,c=e[x][i].se;;
if (vis[y]) continue;
dfs(y);
if (f[y][]+c<=f[y][]) {num--;tot=tot+f[y][]+c;}
else
{
tot=tot+f[y][];
ll o=f[y][]+c-f[y][];
del.pb(o);
h[x].push(o);
sum[x]=sum[x]+o;
}
}
upd1(x,max(0ll,num),add);
f[x][]=tot+sum[x];
upd1(x,max(0ll,num-),add);
f[x][]=tot+sum[x];
for (ll i=;i<add.size();i++) h[x].push(add[i]),sum[x]+=add[i];
for (ll i=;i<del.size();i++) h[x].del(del[i]),sum[x]-=del[i];
}
int main()
{
n=read();
ll ans=;
for (ll i=;i<n;i++)
{
ll x=read(),y=read(),c=read();
e[x].pb({y,c});e[y].pb({x,c});
du[x]++;du[y]++;
ans+=c;
}
printf("%I64d ",ans);
for (ll i=;i<=n;i++)
{
d[du[i]].pb(i);
sort(e[i].begin(),e[i].end(),cmp);
}
nxt[n]=n+;
for (ll i=n-;i>=;i--)
{
if (d[i+].size()) nxt[i]=i+;
else nxt[i]=nxt[i+];
}
memset(vis,,sizeof(vis));
for (ll u=;u<n;u++)
{
for (ll i=;i<d[u].size();i++) dele(d[u][i]);
ans=;D=u;
for (ll i=u+;i<n;i=nxt[i])
for (ll j=;j<d[i].size();j++)
{
if (vis[d[i][j]]) continue;
dfs(d[i][j]);
ans=ans+f[d[i][j]][];
}
for (ll i=u+;i<n;i=nxt[i])
for (ll j=;j<d[i].size();j++) vis[d[i][j]]=;
printf("%I64d ",ans);
}
return ;
}
[codeforces contest 1119 F] Niyaz and Small Degrees 解题报告 (树形DP+堆)的更多相关文章
- 【codeforces contest 1119 F】Niyaz and Small Degrees
题目 描述 \(n\) 个点的树,每条边有一个边权: 对于一个 \(X\) ,求删去一些边后使得每个点的度数 \(d_i\) 均不超过 \(X\) 的最小代价: 你需要依次输出 \(X=0 \to n ...
- 树形DP ---- Codeforces Global Round 2 F. Niyaz and Small Degrees引发的一场血案
Aspirations:没有结果,没有成绩,acm是否有意义?它最大的意义就是让我培养快速理解和应用一个个未知知识点的能力. ————————————————————————————————————— ...
- Codeforces Round #384 (Div. 2)D - Chloe and pleasant prizes 树形dp
D - Chloe and pleasant prizes 链接 http://codeforces.com/contest/743/problem/D 题面 Generous sponsors of ...
- Codeforces Round #551 (Div. 2) D. Serval and Rooted Tree (树形dp)
题目:http://codeforces.com/contest/1153/problem/D 题意:给你一棵树,每个节点有一个操作,0代表取子节点中最小的那个值,1代表取子节点中最大的值,叶子节点的 ...
- Codeforces Round #419 (Div. 2) E. Karen and Supermarket(树形dp)
http://codeforces.com/contest/816/problem/E 题意: 去超市买东西,共有m块钱,每件商品有优惠卷可用,前提是xi商品的优惠券被用.问最多能买多少件商品? 思路 ...
- 2017 Multi-University Training Contest - Team 1 1003&&HDU 6035 Colorful Tree【树形dp】
Colorful Tree Time Limit: 6000/3000 MS (Java/Others) Memory Limit: 131072/131072 K (Java/Others)T ...
- 2015 Multi-University Training Contest 6 solutions BY ZJU(部分解题报告)
官方解题报告:http://bestcoder.hdu.edu.cn/blog/2015-multi-university-training-contest-6-solutions-by-zju/ 表 ...
- codeforces 519C. A and B and Team Training 解题报告
题目链接:http://codeforces.com/contest/519/problem/C 题目意思:给出 n 个 experienced participants 和 m 个 newbie ...
- codeforces 454B. Little Pony and Sort by Shift 解题报告
题目链接:http://codeforces.com/problemset/problem/454/B 题目意思:给出一个序列你 a1, a2, ..., an. 问每次操作只能通过将最后一个数拿出来 ...
随机推荐
- 元信息标记---meta
位于<head></head>之间 1.设置页面关键字: <meta name="keywords" content="输入具体关键字&qu ...
- AI不与人为敌
业界广为流传着一句话:有多少人工就有多少智能. 其实还应该有一句话:有多少付出就因该有多少回报.公正是世界永恒的话题. 一.人工智能还是人工愚蠢 科技从来没有善恶,也不会杀人,愚蠢的人比聪明的人做的错 ...
- js 二级联动
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...
- MySQL创建临时表
drop TEMPORARY table if EXISTS temp_table; create TEMPORARY table temp_table( id int not null, usern ...
- github+hexo(window10)
一.申请github账户 二.先安装node.js.git 本地: 三.安装hexo(建立静态网页,用Markdown写博客) 1.创建文件地址 在合适的地方新建一个文件夹,用来存放自己的博客文件,比 ...
- vfs:open.c 源码学习
nameidata路径查找辅助结构 open.c @do_sys_open @get_unused_fd_flags @do_filp_open 1.开始填充nameidata 2.开始填充file ...
- swift UITableViewCell 中的单选控制样式
我昨天在网上找了一晚上的资料,但是大多都是OC得语法,swift资料实在是太少了,使得我这个刚入门swift的彩笔好不吃力,后面一直各种翻阅资料,终于让我找到了 visibleCells 这个方法,直 ...
- 配置Jupyter
前几天见同学有用Jupyter notebook的,有点喜欢,于是今天自己配了一下. Jupyter是一个非常好用编辑器,因为Jupyter notebook 不仅可以编写代码运行,并且可以直接在代码 ...
- struts2中<jsp:forward>跳转时报404错误的问题
index.jsp页面: <jsp:forward page="show.action"></jsp:forward> 在struts.x ...
- c# 数组 字符串 C#中判断字符串中包含某个字符
string str = "1,2,3,4,5,6,7"; string[] strArray = str.Split(','); //字符串转数组 ...