博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
[codeforces contest 1119 F] Niyaz and Small Degrees 解题报告 (树形DP+堆)
阅读量:4621 次
发布时间:2019-06-09

本文共 2052 字,大约阅读时间需要 6 分钟。

interlinkage:

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
#include
#include
#include
#include
#include
#define fi first#define se second#define pb push_backusing namespace std;typedef long long ll;typedef pair
pll;const ll N=250005;ll n;ll du[N],nxt[N],vis[N];ll sum[N];vector
e[N];vector
d[N];inline ll read(){ char ch=getchar();ll s=0,f=1; while (ch<'0'||ch>'9') { if (ch=='-') f=-1;ch=getchar();} while (ch>='0'&&ch<='9') {s=(s<<3)+(s<<1)+ch-'0';ch=getchar();} return s*f;}bool cmp(pll x,pll y) { return du[x.fi]
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
&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]=1; for (ll i=0;i
add,del; add.clear();del.clear(); ll siz=e[x].size(),tot=0; while (st[x]
<=D) st[x]++; for (ll i=st[x];i
=1;i--) { if (d[i+1].size()) nxt[i]=i+1; else nxt[i]=nxt[i+1]; } memset(vis,0,sizeof(vis)); for (ll u=1;u

转载于:https://www.cnblogs.com/xxzh/p/10698393.html

你可能感兴趣的文章
[正则表达式]难点和误区
查看>>
217. Contains Duplicate
查看>>
hadoop遇到问题总结
查看>>
Windows下手动安装redis服务
查看>>
把 MongoDB 当成是纯内存数据库来使用(Redis 风格)
查看>>
PyTorch 1.0 中文官方教程:使用ONNX将模型从PyTorch传输到Caffe2和移动端
查看>>
LeetCode 4Sum
查看>>
BBC-The Race and a quiz
查看>>
大端小端
查看>>
IntelliJ IDEA 把java项目导出成可执行的jar
查看>>
DynamicReports
查看>>
鼠标经过图像改变实现
查看>>
二分查找法
查看>>
Spring3升级到Spring4时, 运行时出现找不到MappingJacksonHttpMessageConverter的情况
查看>>
详解缓冲区溢出攻击以及防范方法
查看>>
分布式事务解决方案(一) 2阶段提交 & 3阶段提交 & TCC
查看>>
android之网格布局和线性布局实现注册页面
查看>>
BZOJ 1014: [JSOI2008]火星人prefix( splay + hash )
查看>>
安装ejabberd2并配置MySQL为其数据库
查看>>
angular repeat
查看>>