打VP的时候由于CXR和XRY切题太快了导致我只能去写后面的题了

然而VP的时候大概还有一小时时想出了\(O(n^2\log n)\)的暴力,然后过了二十分钟才想到删点的优化

结果细节很多当然是写不出来的了,写完加调花了一个多小时吧,真的比赛时还是没什么用的说

首先我们讲一下暴力做法,考虑直接枚举最大的点度数,我们考虑DP删边,设\(f_{x,0/1}\)表示\(x\)的子树内所有点度数小于限制并且\(0/1\)表示与父亲的边是否选择的最小答案

考虑对于\(f_{x,0}\)转移,我们可以把一个点\(x\)的所有儿\(y\)按照\(f_{y,1}+v_{x,y}-f_{y,0}\)排序,然后选择前\(deg_x-lim\)小的\(f_{y,1}+v_{x,y}\),剩下的选\(\min(f_{y,1}+v_{x,y},f_{y,0})\)

同理,对于\(f_{x,1}\)就是留出一个,选前\(deg_x-lim-1\)小的

但是容易发现这样的复杂度是\(O(n^2\log n)\)的,我们细细一想容易发现不合法的点数变得越来越少

换句话说,就是我们需要DP处理的点越来越少了,容易想到如果我们此时把不必要的点都删掉了,那么整个DP要遍历的点就是\(\sum_{i=0}^{n-1} \sum_{j=1}^n [i\le deg_j]=2n-2\)级别的

所以总体复杂度\(O(n\log n)\),实现上用了multiset来代替可删除堆(怕手开两个优先队列太慢了)

CODE

#include<cstdio>
#include<vector>
#include<utility>
#include<set>
#include<algorithm>
#define RI register int
#define CI const int&
#define pb push_back
#define mp make_pair
#define fi first
#define se second
using namespace std;
const int N=250005;
typedef long long LL;
typedef pair <int,int> pi;
vector <pi> V[N]; vector <int> D[N],Ext[N]; multiset <LL> s[N];
LL sum[N],f[N][2],t,ans; int n,x,y,z,deg[N],pos[N],size[N]; bool vis[N];
inline void addedge(CI x,CI y,CI z)
{
V[x].pb(mp(y,z)); ++deg[x]; V[y].pb(mp(x,z)); ++deg[y];
}
inline bool cmp(const pi& x,const pi& y)
{
return deg[x.fi]<deg[y.fi];
}
inline int max(CI a,CI b)
{
return a>b?a:b;
}
inline void insert(CI x,LL y)
{
s[x].insert(y); ++size[x]; sum[x]+=y;
}
inline void remove(CI x,LL y)
{
s[x].erase(s[x].find(y)); --size[x]; sum[x]-=y;
}
inline void DFS(CI now,CI lim)
{
int td=deg[now]-lim; vis[now]=1; while (size[now]>max(td,0)) remove(now,*s[now].rbegin());
while (pos[now]<deg[now]&&deg[V[now][pos[now]].fi]<=lim) ++pos[now];
LL ret=0; vector <LL> TA,TB; for (RI i=pos[now];i<deg[now];++i)
{
int to=V[now][i].fi,val=V[now][i].se; if (vis[to]) continue; DFS(to,lim);
if ((t=f[to][1]+val-f[to][0])<=0) --td,ret+=f[to][1]+val;
else ret+=f[to][0],TA.pb(t),insert(now,t);
}
while (size[now]>max(td,0)) TB.pb(t=*s[now].rbegin()),remove(now,t); f[now][0]=ret+sum[now];
while (size[now]>max(td-1,0)) TB.pb(t=*s[now].rbegin()),remove(now,t); f[now][1]=ret+sum[now];
while (!TB.empty()) insert(now,TB.back()),TB.pop_back();
while (!TA.empty()) remove(now,TA.back()),TA.pop_back();
}
int main()
{
//freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout);
RI i,j; for (scanf("%d",&n),i=1;i<n;++i)
scanf("%d%d%d",&x,&y,&z),addedge(x,y,z),ans+=z;
for (i=1;i<=n;++i) sort(V[i].begin(),V[i].end(),cmp);
for (i=1;i<=n;++i) D[deg[i]].pb(i);
for (i=1;i<=n;++i) for (j=1;j<deg[i];++j) Ext[j].pb(i);
for (printf("%I64d ",ans),i=1;i<n;++i)
{
for (int x:D[i]) { vis[x]=1; for (pi it:V[x]) if (!vis[it.fi]) insert(it.fi,it.se); } ans=0;
for (int x:Ext[i]) if (!vis[x]) DFS(x,i),ans+=f[x][0]; printf("%I64d ",ans); for (int x:Ext[i]) vis[x]=0;
}
return 0;
}

最新文章

  1. Metro-Ural119递推
  2. wifi强度数据采集器(android)
  3. 在PHP中无法连接Memcached的解决办法
  4. linux vi 删除多行的方法
  5. CentOS6.5安装iftop
  6. 【转】实现RTP协议的H.264视频传输系统
  7. 剑指offer(07)-调整数组顺序使奇数位于偶数前面【转】
  8. 【Executor】配置ThreadPoolExecutor
  9. C#根据日期DateTime和持续时间int找到日期
  10. 【技术贴】Maven打包文件增加时间后缀
  11. D其他项目打电话AL工程EF Model
  12. 导入导出Mysql数据库、表结构、表数据
  13. js冒泡排序,数组去重
  14. LeakCanary使用手册
  15. Grafana+Prometheus打造全方位立体监控系统
  16. Linux包系列的知识(附:Ubuntu16.04升级到18.04的案例)
  17. IDAPython教程(二)
  18. 修改ini文件的批处理
  19. Java基础&amp;面向对象(二)
  20. 使用SonarCloud对.NET Core项目进行静态代码分析

热门文章

  1. 20个Flutter实例视频教程-第06节: 酷炫的路由动画-2
  2. yzm10铺瓷砖 一只小蜜蜂 ycb与取款机
  3. LeetCode: 463 Island Perimeter(easy)
  4. Server.MapPath()相关
  5. 换装demo随手记
  6. TopCoder 14084 BearPermutations2【笛卡尔树+dp】
  7. [Xcode 实际操作]一、博主领进门-(7)使用不同类型的iOS模拟器
  8. 简单搭建webMagic爬虫步骤
  9. C 语言实例 - 计算 int, float, double 和 char 字节大小
  10. 测试 | 单元测试工具 | JUnit | 参数化