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;
}
上一篇:USACO翻译:USACO 2013 NOV Silver三题


下一篇:Latin-1字符集