[MX-X3-T5 & RiOI-4] Countless J-Light Decomposition Solution
看题以为自己会了,写代码的时候发现有细节没考虑清楚,复杂度写挂了以为被卡常了,调用并查集函数还手残打错了,浪费大半个下午。NOI 之后属于越训越菜了 QwQ。
回到这个题,首先这个题当 固定时做法是显然的,我们自底向上考虑,每次一定是 ban 掉连向当前最长链最大子树的 条边。
发现只有当 时一个点才有考虑价值,而 是 级别的。建出虚树,然后每个点相当于删除若干个边权,加入若干个新边权,求第 大。可以使用平衡树维护。做完了,复杂度 。
如果我直接写虚树+平衡树,我就不用浪费这个下午了,但是我脑子一抽突然不想写十级算法。所以我们可以考虑用并查集维护当前还存在的 的点,再开一颗并查集,按照 dfs 序倒序遍历,每次删去在当前所有点子树的关键点,就可以实现跟虚树同样的功能且免去了常数大的递归,但是复杂度其实是带一个小 或 的。
平衡树也好难写,每次加入删除之后还要删除加入回去常数大飞,我们考虑用常数更小的算法。注意到题目对于一个已经准备好的数组形如删除若干个,加入若干个,然后还要回退回去。我们考虑经典的用堆维护第 大,所以我们只需要开一个小根堆存储最大的 个。
使用可删堆不够优美,因为还是要回退回去。我们考虑用两个堆结构拼成一个堆,把一个点下面的所有边排序一下,取后面若干个直接作为其中一个堆,由于原本存在的边只会被删,所以这里就是直接用一个指针就可以实现弹堆了。然后你就可以做到洛谷最快了。
我是在这里干些什么啊 \yun。
#include <queue> #include <cstdio> #include <vector> #include <cassert> #include <algorithm> #include <functional> #define fi first #define se second using namespace std; int read(){ /* reading... */ } const int N=200003; typedef long long ll; typedef pair<int,int> pii; typedef pair<ll,int> pli; inline void chmx(ll &x,ll v){if(x<v) x=v;} inline void chmn(ll &x,ll v){if(x>v) x=v;} int n; vector<pii> adj[N],tr[N],vec[N]; int dfn[N],o[N],sz[N],ps[N],num; void dfs(int u,int fa){ o[dfn[u]=++num]=u; sz[u]=1; for(auto [v,w]:adj[u]) if(v^fa){ dfs(v,u); tr[u].emplace_back(w,v); vec[u].emplace_back(v,w); sz[u]+=sz[v]; } sort(tr[u].begin(),tr[u].end()); int tt=0; for(auto [w,v]:tr[u]) ps[v]=tt++; } int f[N],g[N]; bool del[N]; int rt(int x){ if(f[x]==x) return x; return f[x]=rt(f[x]); } int go(int x){ if(g[x]==x) return x; return g[x]=go(g[x]); } int stk[N],tp; int que[N],tl; ll dp[N],ed[N]; int main(){ n=read(); for(int i=1;i<n;++i){ int u=read(),v=read(),w=read(); adj[u].emplace_back(v,w); adj[v].emplace_back(u,w); } dfs(1,0); for(int i=n;i;--i) stk[++tp]=o[i]; for(int i=1;i<=n+1;++i) f[i]=i; g[n+1]=n+1; int cnt=0; for(int x=0;x<n;++x){ ll res=0; for(int i=1;i<=tp;++i) g[dfn[stk[i]]]=dfn[stk[i]]; for(int i=1;i<=tp;++i){ int u=stk[i]; int ss=tr[u].size(); if(ss<=x){f[dfn[u]]=dfn[u]+1;continue;} g[dfn[u]]=dfn[u]; vector<pii> tmp; que[++tl]=u; int p=ss-x-1; ll tdp=0; priority_queue<ll,vector<ll>,greater<ll>> pq; for(auto [v,w]:vec[u]){ ed[v]=0;bool fl=0; for(int t=go(rt(dfn[v]));t<dfn[v]+sz[v];t=go(t)) chmx(ed[v],dp[o[t]]+w),fl=1,g[t]=rt(t+1),chmx(tdp,dp[o[t]]); if(fl){ tmp.emplace_back(v,w); del[v]=1;pq.emplace(ed[v]); if(ps[v]<p){ if(!pq.empty()&&(p==ss||tr[u][p].fi>pq.top())) pq.pop(); else ++p; } while(p<ss&&del[tr[u][p].se]) ++p; } } dp[u]=1e18; if(p<ss) chmn(dp[u],tr[u][p].fi); if(!pq.empty()) chmn(dp[u],pq.top()); vec[u].swap(tmp); for(auto [v,w]:vec[u]) del[v]=0; chmx(dp[u],tdp); chmx(res,dp[u]); } tp=tl;tl=0; for(int i=1;i<=tp;++i) stk[i]=que[i]; printf("%lld ",res); } putchar('\n'); return 0; }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 按钮权限的设计及实现