P11038 【MX-X3-T5】「RiOI-4」Countless J-Light Decomposition

我们可以发现,对于一个点 \(u\),如果当前是 \(i\) 重且 \(u\) 的孩子个数比 \(i\) 少那么我们可以认为这个点不会对答案产生贡献。这给了我们思路。我们可以考虑对于当前枚举孩子个数,对于仍需要考虑哪些选的建虚树。由于一个点最多会被遍历孩子个数次,那么关键点总和还是 \(n\) 的。

我们只需要考虑关键点如何动规。考虑设 \(f_u\) 表示当前所有到 \(u\) 的最大贡献。那么对于不是关键点的,显然有 \(f_{u}=\max_v f_v\)。对于是关键点的,我们可以按 \(f_v+E(u,v)\) 排序,那么更新为:

\[f_u=\max(\max_v f_v,f_{v_{i+1}}+E(u,v_{i+1})) \]

但是我们发现,虽然关键点总和是对的,但是上面那个 \(v\) 仍要从最开始的树进行访问。但是发现,只有存在关键点的子树 \(f_v\) 才不为 \(0\)。所以我们可以考虑先提前用数据结构存上所有的 \(E\),之后对于每一颗虚树的新关键点,我们删掉对应的 \(E\) 然后插入新的 \(f+E\) 即可。

我们需要一个能够查第 \(k\) 大,可随机删随机插入的数据结构。当然可以手写平衡树或者权值线段树。但是这里我们可以直接使用对顶 multiset 来存。我们开两个 multiset,其中一个存前 \(k\) 大的数,另一个存剩下的数。那么我们只需要写一个平衡函数来平衡两个之间的大小关系即可,插入就可以先插入到大 multiset,然后平衡。删除就找这个元素在哪里,删掉之后平衡即可。这样会比平衡树好写一些。

时间复杂度 \(O(n\log n)\)

#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=(a);i<=(b);++i)
using namespace std;
typedef long long ll;
const int MAXN=2.5e5+5;
int n;
vector<pair<int,int>>adj[MAXN];
ll mi[MAXN][20];
int lg[MAXN];
int fa[MAXN][20],st[MAXN][20],dfn[MAXN],dfntot,dep[MAXN],sn[MAXN];
ll sm[MAXN];
multiset<ll>sa[MAXN],sb[MAXN];
int up=1;
void insert(int id,ll nw){
	sa[id].insert(nw);
	while(sa[id].size()>up){
		sb[id].insert(*sa[id].begin());
		sa[id].erase(sa[id].begin());
	}
}
void erase(int id,ll x){
	if(sa[id].count(x)){
		sa[id].erase(sa[id].find(x));
	}else if(sb[id].count(x)){
		sb[id].erase(sb[id].find(x));
	}
	while(sa[id].size()<up&&!sb[id].empty()){
		auto it=sb[id].end();
		it--;
		sa[id].insert(*it);
		sb[id].erase(it);
	}
}
void init(int u,int f){
    dep[u]=dep[f]+1;
    dfn[u]=++dfntot;
    st[dfntot][0]=f;
	fa[u][0]=f;
	rep(i,1,19){
		fa[u][i]=fa[fa[u][i-1]][i-1];
	}
    for(auto eg:adj[u]){
        int v=eg.first,w=eg.second;
        if(v==f){
            continue;
        }
        sn[u]++;
        sm[v]=sm[u]+w;
		insert(u,w);
        init(v,u);
    }
}
int gno(int u,int v){
    return dep[u]<dep[v]?u:v;
}
int lca(int u,int v){
    if(u==v){
        return u;
    }
    u=dfn[u],v=dfn[v];
    if(u>v){
        swap(u,v);
    }
    u++;
    int j=lg[v-u+1];
    return gno(st[u][j],st[v-(1<<j)+1][j]);
}
vector<pair<int,ll>>e[MAXN];
bool cmp(int u,int v){
    return dfn[u]<dfn[v];
}
bool gd[MAXN];
void build(vector<int>s){
    s.push_back(1);
    sort(s.begin(),s.end(),cmp);
    s.erase(unique(s.begin(),s.end()),s.end());
    int nm=int(s.size())-2;
    rep(i,0,nm){
        s.push_back(lca(s[i],s[i+1]));
    }    
    sort(s.begin(),s.end(),cmp);
    s.erase(unique(s.begin(),s.end()),s.end());
    for(auto v:s){
        e[v].clear();
    }
    rep(i,0,int(s.size())-2){
        int l=lca(s[i],s[i+1]);
		int val=dep[s[i+1]]-dep[l]-1,nxt=s[i+1];
		for(int j=0;val;++j){
			if(val&1){
				nxt=fa[nxt][j];
			}
			val>>=1;
		}
        e[l].push_back({s[i+1],sm[nxt]-sm[l]});
    }
}
ll f[MAXN];
void dfs(int u){
	f[u]=0;
	for(auto eg:e[u]){
		dfs(eg.first);
		erase(u,eg.second);
		insert(u,eg.second+f[eg.first]);
		f[u]=max(f[u],f[eg.first]);
	}
	while(sa[u].size()<up&&!sb[u].empty()){
		auto it=sb[u].end();
		it--;
		sa[u].insert(*it);
		sb[u].erase(it);
	}
	if(sa[u].size()>=up){
		f[u]=max(f[u],(*sa[u].begin()));
	}
	for(auto eg:e[u]){
		erase(u,eg.second+f[eg.first]);
		insert(u,eg.second);
	}
}
int nm[MAXN];
int main(){
    ios::sync_with_stdio(false);
    cin.tie(0);cout.tie(0);
    cin>>n;
    rep(i,2,n){
        lg[i]=lg[i>>1]+1;
    }
    rep(i,1,n-1){
        int u,v,w;
        cin>>u>>v>>w;
        adj[u].push_back({v,w});
        adj[v].push_back({u,w});
    }
    init(1,0);
    rep(j,1,lg[n]){
        rep(i,1,n-(1<<j)+1){
            st[i][j]=gno(st[i][j-1],st[i+(1<<(j-1))][j-1]);
        }
    }
    rep(i,1,n){
        nm[i]=i;
    }
    sort(nm+1,nm+n+1,[](int x,int y){
        return sn[x]<sn[y];
    });
    int j=1;
    rep(i,0,n-1){
        while(j<=n&&sn[nm[j]]<=i){
            ++j;
        }
        if(j==n+1){
            cout<<0<<" \n"[i==n];
            continue;
        }
        vector<int>s;
        rep(vv,j,n){
            s.push_back(nm[vv]);
            gd[nm[vv]]=true;
        }
        build(s);
		up=i+1;
		dfs(1);
		cout<<f[1]<<" \n"[i==n];
        rep(vv,j,n){
            gd[nm[vv]]=false;
        }
    }
    return 0;
}
posted @ 2025-12-11 21:21  tanghg  阅读(8)  评论(0)    收藏  举报