码迷,mamicode.com
首页 > 其他好文 > 详细

题目:[Tree]树中的配对(set&思维)

时间:2020-01-20 22:32:21      阅读:57      评论:0      收藏:0      [点我收藏+]

标签:names   并且   ext   inline   struct   没有   mes   min   包括   

题目

传送门

思路

首先我们解决第一个问题

怎么使值最大?

这个可以通过公式变形来解决

\(ans=\sum_{i=1}^{n}(dep_i+dep_{p_i}-2*dep_{lca_{i,p_i}})=2*\sum_{i=1}^{n}dep_i-2*\sum_{i=1}^{n}dep_{lca_{i,p_i}}\)

下面我们看看这能得到什么

p序列是客观存在的,这是与哪个节点是根节点是没有关系的

所以对于一个固定的根节点,他的最大值也是答案

然而我们已知,对于一个根节点,式子的前半部分的值是固定的,所以我们使后一段尽可能的小,当后一段最小时,这就是答案,并且这个答案就是最大值

为了方便,我们就将根结点定为重心,后半部分很容依旧能得到0

第一部分就解决了

下面来说第二部分

对于编号,我们直接找最小的编号就行了

但是要注意一个情况,

我们将一个点拆成一个入点和出点

就是我们将连接看成单项的

我们定义\(in_u\text{和}out_u\)表示第u个子树还没有匹配的出点,和还没有匹配的入点数量

我们考虑我们是怎样将使最后一段等于0的,也就是选的两个点必须不在同一颗子树

也就是对于任何一颗子树我们必须满足

\(in_u+out_u\le\sum_{i=1}^{i\in 子树}(in_i+out_i)-in_u-out_u\)

也就是说,当某一颗子树\(i\)使这个等式取等号的时候,我们对于当前点,

如果当前点不在这颗最大的子树内,这个点必须与子树\(i\)中的某一个节点匹配

对于\(in\)\(out\)的维护用线段树维护,

最后我们需要将根特殊考虑,为什么?

因为根可以和任意节点匹配,包括自己

代码

#include<iostream>
#include<vector>
#include<set>
using namespace std;
struct node1
{
    int e;
    long long w;
};
struct node_set
{
    int e;
    int w;
    friend bool operator < (const node_set &a,const node_set &b)
    {
        return a.w<b.w;
    }
};
struct node_tre
{
    int l;
    int r;
    int maxx;
    int s1;//未匹配的入点
    int s2;//未匹配的出点

}tre[400005];
int n;
int rt;
int siz[100005];
int bel[100005];
long long dep[100005];
vector<node1> g[100005];
long long ans;
set<int> in[100005];    
set<node_set> minn;
void build(int l,int r,int k)
{
    tre[k].l=l;
    tre[k].r=r;
    tre[k].maxx=tre[k].s1=tre[k].s2=0;
    if(l==r)
    {
        tre[k].maxx=in[l].size()*2;
        tre[k].s1=in[l].size();
        tre[k].s2=in[l].size();
        return;
    }
    int mid=(l+r)>>1;
    build(l,mid,k<<1);
    build(mid+1,r,k<<1|1);
    tre[k].maxx=max(tre[k<<1].maxx,tre[k<<1|1].maxx);
    tre[k].s1=tre[k<<1].s1+tre[k<<1|1].s1;
    tre[k].s2=tre[k<<1].s2+tre[k<<1|1].s2;
}
void delet1(int u,int k)//减去入点
{
    if(tre[k].l>u||tre[k].r<u)
        return ;
    if(tre[k].l==tre[k].r)
    {
        tre[k].s1--;
        tre[k].maxx=tre[k].s1+tre[k].s2;
        return;
    }
    delet1(u,k<<1);
    delet1(u,k<<1|1);
    tre[k].maxx=max(tre[k<<1].maxx,tre[k<<1|1].maxx);
    tre[k].s1=tre[k<<1].s1+tre[k<<1|1].s1;
    tre[k].s2=tre[k<<1].s2+tre[k<<1|1].s2;
}
void delet2(int u,int k)//减去出点
{
    if(tre[k].l>u||tre[k].r<u)
        return ;
    if(tre[k].l==tre[k].r)
    {
        tre[k].s2--;
        tre[k].maxx=tre[k].s1+tre[k].s2;
        return;
    }
    delet2(u,k<<1);
    delet2(u,k<<1|1);
    tre[k].maxx=max(tre[k<<1].maxx,tre[k<<1|1].maxx);
    tre[k].s1=tre[k<<1].s1+tre[k<<1|1].s1;
    tre[k].s2=tre[k<<1].s2+tre[k<<1|1].s2;
}
int ask(int k,int fin)
{
    if(tre[k].maxx!=fin)
        return 0;
    if(tre[k].l==tre[k].r)
        return tre[k].l;
    int t=ask(k<<1,fin);
    if(t)
        return t;
    return ask(k<<1|1,fin);
}
void dfs_fouc(int u,int fa)
{
    int maxx=-1;
    siz[u]=1;
    for(int i=0;i<g[u].size();i++)
    {
        int v=g[u][i].e;
        if(v!=fa)
        {
            dfs_fouc(v,u);
            siz[u]+=siz[v];
            maxx=max(maxx,siz[v]);
        }
    }
    maxx=max(maxx,n-siz[u]);
    if(n/2>=maxx)
        rt=u;
}
void dfs_dep(int u,int fa)
{       
    ans+=dep[u]*2;
    for(int i=0;i<g[u].size();i++)
    {
        int v=g[u][i].e;
        if(v!=fa)
        {
            dep[v]=dep[u]+g[u][i].w;
            dfs_dep(v,u);
        }
    }
}
void dfs_bel(int u,int fa,int _ind)
{
    bel[u]=_ind;
    in[_ind].insert(u);
    for(int i=0;i<g[u].size();i++)
    {
        int v=g[u][i].e;
        if(v!=fa)
            dfs_bel(v,u,_ind);
    }
}
int main()
{
    ios::sync_with_stdio(false);
    cin>>n;
    for(int i=1;i<n;i++)
    {
        int u,v;
        long long w;
        cin>>u>>v>>w;
        g[u].push_back((node1){v,w});
        g[v].push_back((node1){u,w});
    }
    dfs_fouc(1,0);
    dfs_dep(rt,0);
    for(int i=0;i<g[rt].size();i++)
        dfs_bel(g[rt][i].e,rt,i+1);
    bel[rt]=g[rt].size()+1;
    in[g[rt].size()+1].insert(rt);
    for(int i=1;i<=g[rt].size()+1;i++)
    {
        set<int>::iterator it=in[i].begin();
        minn.insert((node_set){i,*it});
    }
    cout<<ans<<'\n';
    build(1,g[rt].size()+1,1);
    for(int i=1;i<=n;i++)
    {
        int u=ask(1,tre[1].maxx);
        if(tre[1].maxx>=n-i+1&&(bel[i]!=u&&u!=g[rt].size()+1))
        {
            set<int>::iterator it=in[u].begin();
            int t=*it;
            cout<<t<<' ';
            in[u].erase(in[u].find(t)); 
            minn.erase(minn.find((node_set){u,t}));
            delet1(u,1);
            delet2(bel[i],1);
            if(!in[u].empty())
            {
                it=in[u].begin();
                minn.insert((node_set){u,*it});
            }
        }
        else
        {
            set<node_set>::iterator it1=minn.begin();
            node_set t=*it1;
            if(t.e==bel[i]&&t.w!=rt)
            {
                minn.erase(it1);
                set<node_set>::iterator it2=minn.begin();
                node_set t2=*it2;
                minn.insert(t);
                t=t2;
            }
            cout<<t.w<<' ';
            delet1(t.e,1);
            delet2(bel[i],1);
            minn.erase(minn.find(t));
            in[t.e].erase(in[t.e].find(t.w));
            if(!in[t.e].empty())
            {
                set<int>::iterator it=in[t.e].begin();
                minn.insert((node_set){t.e,*it});
            }
        }
    }
    return 0;
}

题目:[Tree]树中的配对(set&思维)

标签:names   并且   ext   inline   struct   没有   mes   min   包括   

原文地址:https://www.cnblogs.com/loney-s/p/12219353.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!