zoukankan      html  css  js  c++  java
  • CF1119F Niyaz and Small Degrees【treedp+堆】

    如果枚举d来dp,那么就是设f[u][0/1]为u点不断/断掉和父亲的边,然后优先选取f[v][1]+w(u,v)<=f[v][0]的,如果断掉这些度数还是多就用一个堆维护剩下的按f[v][1]+w(u,v)-f[v][0]从大到小取(负的)
    然后注意到设当前要求度数是d,那么度数<=d的点全都不用dp,所以可以直接把贡献累加到和他相邻的点上然后断掉边,这样一共算Σ度数ci,就是O(nlogn)的了

    #include<iostream>
    #include<cstdio>
    #include<queue>
    #include<vector>
    #include<algorithm>
    using namespace std;
    const int N=300005;
    int n,du,v[N],d[N],s[N],ne[N];
    long long ans,sm[N],f[N][2];
    vector<pair<int,int> >e[N];
    vector<int>a[N];
    int read()
    {
    	int r=0,f=1;
    	char p=getchar();
    	while(p>'9'||p<'0')
    	{
    		if(p=='-')
    			f=-1;
    		p=getchar();
    	}
    	while(p>='0'&&p<='9')
    	{
    		r=r*10+p-48;
    		p=getchar();
    	}
    	return r*f;
    }
    struct dui
    {
    	priority_queue<long long>p,q;
    	void push(long long x)
    	{
    		q.push(x);
    	}
    	void erase(long long x)
    	{
    		p.push(x);
    	}
    	int top()
    	{
    		while(!q.empty()&&!p.empty()&&q.top()==p.top())
    			q.pop(),p.pop();
    		return q.top();
    	}
    	void pop()
    	{
    		top();
    		q.pop();
    	}
    	int size()
    	{
    		return q.size()-p.size();
    	}
    	bool empty()
    	{
    		return q.size()==p.size();
    	}
    }q[N];
    bool cmp(const pair<int,int>&a,const pair<int,int>&b)
    {
    	return d[a.first]<d[b.first];
    }
    void add(int u,int v,int w)
    {
    	e[u].push_back(make_pair(v,w));
    	e[v].push_back(make_pair(u,w));
    }
    void dfs(int u,int fa)
    {
    	v[u]=1;
    	int r=d[u]-du;
    	long long sum=0;
    	vector<long long>ad,de;
    	while(q[u].size()>r)
    		sm[u]-=q[u].top(),q[u].pop();
    	while(s[u]<e[u].size()&&d[e[u][s[u]].first]<=du)
    		s[u]++;
    	for(int i=s[u],len=e[u].size();i<len;i++)
    		if(!v[e[u][i].first]&&e[u][i].first!=fa)
    		{
    			dfs(e[u][i].first,u);
    			if(f[e[u][i].first][1]+e[u][i].second<=f[e[u][i].first][0])
    				r--,sum+=f[e[u][i].first][1]+e[u][i].second;
    			else
    			{
    				sum+=f[e[u][i].first][0];
    				long long nw=f[e[u][i].first][1]+e[u][i].second-f[e[u][i].first][0];
    				q[u].push(nw);
    				sm[u]+=nw;
    				de.push_back(nw);
    			}
    		}
    		while(q[u].size()>max(0,r))
    			sm[u]-=q[u].top(),ad.push_back(q[u].top()),q[u].pop();
    		f[u][0]=sum+sm[u];
    		r--;
    		while(q[u].size()>max(0,r))
    			sm[u]-=q[u].top(),ad.push_back(q[u].top()),q[u].pop();
    		f[u][1]=sum+sm[u];
    		for(int i=0,len=ad.size();i<len;i++)
    			q[u].push(ad[i]),sm[u]+=ad[i];
    		for(int i=0,len=de.size();i<len;i++)
    			q[u].erase(de[i]),sm[u]-=de[i];
    }
    int main()
    {
    	n=read();
    	for(int i=1;i<n;i++)
    	{
    		int x=read(),y=read(),z=read();
    		add(x,y,z);
    		d[x]++,d[y]++;
    		ans+=z;
    	}
    	for(int i=1;i<=n;i++)
    	{
    		a[d[i]].push_back(i);
    		sort(e[i].begin(),e[i].end(),cmp);
    	}
    	ne[n]=n+1;
    	for(int i=n-1;i>=1;i--)
    	{
    		if(a[i+1].size())
    			ne[i]=i+1;
    		else
    			ne[i]=ne[i+1];
    	}
    	printf("%lld ",ans);
    	for(int i=1;i<n;i++)
    	{
    		for(int j=0,len=a[i].size(),u;j<len;j++)
    		{
    			u=a[i][j];
    			v[u]=1;
    			for(int k=0,le=e[u].size();k<le;k++)
    				if(!v[e[u][k].first])
    					q[e[u][k].first].push(e[u][k].second),sm[e[u][k].first]+=e[u][k].second;
    		}
    		ans=0,du=i;
    		for(int j=i+1;j<=n;j=ne[j])
    			for(int k=0,len=a[j].size();k<len;k++)
    				if(!v[a[j][k]])
    				{
    					dfs(a[j][k],0);
    					ans+=f[a[j][k]][0];
    				}
    		for(int j=i+1;j<=n;j=ne[j])
    			for(int k=0,len=a[j].size();k<len;k++)
    				v[a[j][k]]=0;
    		printf("%lld ",ans);
    	}
    	return 0;
    }
    
  • 相关阅读:
    给力牛人
    设计模式
    微软真的要放弃Windows品牌吗?
    SQL2005 Express 自动安装之命令行
    SQL where之 in 在变量
    数据库求闭包,求最小函数依赖集,求候选码,判断模式分解是否为无损连接,3NF,BCNF
    别浪费了你的大内存[转]
    QQ空间免费养5级花和拥有人参果
    asp.net2 统一搜索引擎关键字编码[转]
    把网速提高4倍的方法和动画教程
  • 原文地址:https://www.cnblogs.com/lokiii/p/10847864.html
Copyright © 2011-2022 走看看