• 【CF1119F】Niyaz and Small Degrees


    题目

    题目链接:https://codeforces.com/problemset/problem/1119/F
    双倍经验:https://www.luogu.com.cn/problem/P7600
    有一个 (n) 个结点的树,每条边有边权,结点度数就是与之相连的边数量。对于 (0 le x < n),删掉一些边使每个结点的度数不大于 (x),求出删掉的边的权值和最小值。
    (nleq 2.5 imes 10^5)

    思路

    为 APIO 出题人辛苦地精心准备高质量原创题目行为点赞!!!/tuu
    不提这一点,我写 (O(n^2log n)) 暴力,数组都是 (O(n)) 的一直告诉我 MLE,吐了。

    (f[x][0/1]) 表示点 (x) 为根的子树内,其中 (x) 与父亲的边不删 / 删时,要求每个点度数不超过 (k) 的最小代价。
    暴力的话就直接先钦定 (x) 与它所有儿子的边都是不删除的,然后删除其中最少 ( ext{deg}[x]-k) 条边。
    那么直接把所有儿子 (y)(f[y][1]+ ext{dis}[x][y]-f[y][0]) 取最小的 ( ext{deg}[x]-k) 个删除,其他都不删除。
    时间复杂度 (O(n^2log n))

    观察到对于点 (x),当 (kgeq ext{deg}[x]) 的时候,(x) 就无关度数限制了,可以任意调整 (x) 的所有边,最小化 (x) 旁边的点的代价。
    我们对于每一个点维护一个堆(用处与上文暴力的堆一样),当求解到要求所有点度数不超过 (k) 时,把 ( ext{deg}[x]=k) 的所有 (x) 拎出来,对于一条边 ((x,y)),把 ( ext{dis}[x][y]) 扔进 (y) 的堆中。
    然后枚举所有度数大于 (k) 的点跑树形 dp,注意不用便利度数不超过 (k) 的点。这个可以用 vector 存图然后给出边排个序。
    注意每次跑完一个点后需要还原这个点的堆,也就是堆中只保留其他度数不超过 (k) 的点到这个点的距离。所以维护两个堆实现可删除堆即可。
    时间复杂度 (O((sum^{n}_{i=1} deg_i)log n)=O(nlog n))
    细节确实有点多,建议阅读代码理解。

    代码

    #include <bits/stdc++.h>
    #define mp make_pair
    #define ST first
    #define ND second
    using namespace std;
    typedef long long ll;
    
    const int N=250010;
    const ll Inf=8e18;
    int n,deg[N],vis[N],id[N];
    ll ans,f[N][2],sum[N];
    priority_queue<ll> q[N],p[N];
    vector<ll> a,b;
    vector<pair<int,ll> > e[N];
    
    bool cmp(int x,int y)
    {
    	return deg[x]<deg[y];
    }
    
    bool cmp1(pair<int,ll> x,pair<int,ll> y)
    {
    	return deg[x.ST]>deg[y.ST];
    }
    
    void add(int from,int to,ll dis)
    {
    	e[from].push_back(mp(to,dis));
    	deg[to]++;
    }
    
    void Erase(int x,ll v=Inf)
    {
    	if (v!=Inf) p[x].push(v),sum[x]-=v;
    	while (q[x].size() && p[x].size() && q[x].top()==p[x].top())
    		q[x].pop(),p[x].pop();
    }
    
    void Push(int x,ll v)
    {
    	q[x].push(v); sum[x]+=v; Erase(x);
    }
    
    void Pop(int x)
    {
    	sum[x]-=q[x].top(); q[x].pop(); Erase(x);
    }
    
    void dfs(int x,int fa,int k)
    {
    	vis[x]=k; f[x][0]=f[x][1]=0;
    	for (int i=0;i<e[x].size();i++)
    	{
    		int v=e[x][i].ST;
    		if (deg[v]<=k) break;
    		if (v!=fa) dfs(v,x,k);
    	}
    	a.clear(); b.clear();
    	int cnt=deg[x]-k;
    	while (q[x].size()-p[x].size()>cnt) Pop(x);
    	for (int i=0;i<e[x].size();i++)
    	{
    		int v=e[x][i].ST; ll dis=e[x][i].ND;
    		if (deg[v]<=k) break;
    		if (v!=fa)
    		{
    			if (f[v][0]<f[v][1]+dis)
    			{
    				f[x][0]+=f[v][0];
    				Push(x,f[v][1]+dis-f[v][0]);
    				a.push_back(f[v][1]+dis-f[v][0]);
    			}
    			else cnt--,f[x][0]+=f[v][1]+dis;
    		}
    	}
    	f[x][1]=f[x][0];
    	for (;q[x].size()-p[x].size()>max(cnt,0);Pop(x))
    		b.push_back(q[x].top());
    	f[x][0]+=sum[x];
    	for (;q[x].size()-p[x].size()>max(cnt-1,0);Pop(x))
    		b.push_back(q[x].top());
    	f[x][1]+=sum[x];
    	for (int i=0;i<b.size();i++) Push(x,b[i]);
    	for (int i=0;i<a.size();i++) Erase(x,a[i]);
    }
    
    int main()
    {
    	memset(vis,-1,sizeof(vis));
    	scanf("%d",&n);
    	for (int i=1,x,y,z;i<n;i++)
    	{
    		scanf("%d%d%d",&x,&y,&z);
    		add(x,y,z); add(y,x,z);
    	}
    	for (int i=1;i<=n;i++)
    	{
    		id[i]=i;
    		sort(e[i].begin(),e[i].end(),cmp1);
    	}
    	sort(id+1,id+1+n,cmp);
    	for (int i=0,j=1;i<n;i++)
    	{
    		for (;j<=n && deg[id[j]]<=i;j++)
    		{
    			int x=id[j];
    			for (int k=0;k<e[x].size();k++)
    			{
    				int v=e[x][k].ST;
    				if (deg[v]<=i) break;
    				Push(v,e[x][k].ND);
    			}
    		}
    		ans=0;
    		for (int k=j;k<=n;k++)
    			if (vis[id[k]]!=i)
    			{
    				dfs(id[k],0,i);
    				ans+=f[id[k]][0];
    			}
    		cout<<ans<<' ';
    	}
    	return 0;
    }
    
  • 相关阅读:
    21. Node.Js Buffer类(缓冲区)-(一)
    20.Node.js EventEmitter的方法和事件
    19.Node.js EventEmitter
    18.Node.js 事件循环
    17.Node.js 回调函数--异步编程
    16.REPL 命令
    15.Node.js REPL(交互式解释器)
    14.NPM 常用命令
    **PHP Notice: Undefined index:...问题的解决方法
    **CI中的order_by在get_where之前
  • 原文地址:https://www.cnblogs.com/stoorz/p/14818918.html
Copyright © 2020-2023  润新知