CF1856E2 PermuTree (hard version)

思路

对于一个子树来说,贡献是 \(\left(sum_{v\in son}[a_v<a_u]\right)\cdot\left(sum_{v\in son}[a_v>a_u]\right)\)。这个式子等价与将子树分为两部分,贡献就是这两部分大小的乘积。

很显然,这两个部分大小越接近 平分 越好,因为他们的和是一定的。

所以现在就转化为一个 \(01\) 背包问题,对每一个子树都做一遍。

但这是 \(O(n^2)\) 的做法,仅可以通过 E1。

由于和是一定的,那么由于大小大于 \(\sqrt n\) 的子树个数不超过 \(\sqrt n\) 个,所以子树大小种类的个数也是 \(\sqrt n\) 级别的。

于是可以转化为多重背包问题。

由于我们只注重能不能分出一种方案,于是我们可以使用 二进制优化 以及 bitset,这样复杂度优化到 \(O\left(\frac{n\sqrt n}\omega\right)\)

注意使用 bitset 时要实时根据大小开,否则空间开不下。这里使用模板元编程。


代码

#include <bits/stdc++.h>
#pragma GCC optimize(2)

using namespace std;

#define int long long

#define fileio(x,y) freopen(x,"r",stdin),freopen(y,"w",stdout)
#define tup tuple<int,int,int>
#define pii pair<int,int>
#define bit(x) bitset<x>
#define pb emplace_back
#define mt make_tuple
#define mp make_pair

const int   mod=998244353;
const int   maxn=1e6+10;

vector<int> road[maxn],son[maxn],vec;
int         n,siz[maxn];
int         tar;

template<int size=1> int solve(int root,int fa)
{
    int nowsize=siz[root]-1,lst=0,cnt=1;
    if(nowsize+5>size) return solve<(min(2*size,1048576ll))>(root,fa);
    sort(son[root].begin(),son[root].end()); vec.clear(); son[root].pb(-1);
    for(int it:son[root])
    {
        if(!lst) { lst=it; continue; }
        if(it!=lst)
        {
            int base=1;
            while(cnt)
            {
                vec.pb(lst*min(cnt,base));
                cnt-=min(cnt,base); base<<=1;
            }
        }
        lst=it,cnt++;
    }
    bitset<size+5> dp; dp.set(size);
    for(int it:vec) dp|=(dp>>it);
    int pos=dp._Find_next(size-nowsize/2-1);
    return (size-pos)*(nowsize-(size-pos));
}

void dfs(int root,int fa)
{
    siz[root]=1;
    for(int v:road[root])
    {
        if(v==fa) continue;
        dfs(v,root); siz[root]+=siz[v],son[root].pb(siz[v]);
    }
    if(son[root].size()<=1) return;
    if(son[root].size()==2) return (void)(tar+=son[root][0]*son[root][1]);
    for(int it:son[root])
        if(it>=(siz[root]-1)/2)
            return (void)(tar+=it*(siz[root]-1-it));
    tar+=solve<8>(root,fa);
    return;
}

void work()
{
    /* Code */
    cin>>n;
    for(int i=1,x,y; i<n; i++) cin>>x,y=i+1,road[x].pb(y),road[y].pb(x);
    // for(int i=1,x,y; i<n; i++) cin>>x>>y,road[x].pb(y),road[y].pb(x);
    dfs(1,0); cout<<tar<<'\n';
    return;
}

signed main()
{
    // fileio("tree.in","tree.out");
    ios::sync_with_stdio(false);
    cin.tie(0);
    int t,stTime=clock();
    t=1;
    while(t--)
        work();
    // cerr<<"Time : "<<(double)(clock()-stTime)/CLOCKS_PER_SEC<<'\n';
    return 0;
} // Texas yyds !!!
posted @ 2024-08-05 20:24  静谧幽蓝  阅读(4)  评论(0编辑  收藏  举报