P12504 「ROI 2025 Day1」树上的青蛙

news/2025/11/10 20:56:01/文章来源:https://www.cnblogs.com/UesugiErii-/p/19208225

树上最大匹配对数,考虑贪心。怎么感觉题解都没有很讲明白复杂度优化的过程,也可能是我太蠢了。

\(d\) 为偶数的情况 \(d\to d-1\) 没有影响,所以只讨论 \(d\) 为奇数。

假设 \(lca(u,v)=w\)\(V_i=\{u|dep_u=i\}\)

\(u\)\(v\) 的路径一定形如 \(u\to p\to v\) 其中 \(p\)\(lca(u,v)\) 到根上路径中的任意一点。从 \(p\) 的角度考虑,假设点对 \((u,v)\) 的路径均为 \(u\to p\to v\),则尽量匹配满足条件且形如 \((u,v)\) 满足 \(dis(u,v)=d\) 的点对是不劣的。

对于 \((u,v),dis(u,v)<d\) 无论将其提至任意祖先 \(p\) 满足 \(dis(u,p)+dis(p,v)\le d\) 时均能匹配(\(dis(u,p)+dis(p,v)=dis(u,v)+2\cdot dis(w,p)\),显然奇偶性不变)。

不考虑奇偶性,\((u,v)\)\(p\) 处匹配需要满足的条件为 \(dis(u,v)+2\cdot dis(w,p)\le d\)。转化一下,对于点 \(u\)\(p\) 处能匹配的 \(v\) 要满足

\(dis(u,v)\le d-2\cdot dis(w,p)\\\to dep_u+dep_v-2\cdot dep_w\le d-2\cdot (dep_w+dep_p-2\cdot dep_p)\\\to dep_v\le d+2\cdot dep_p-dep_u\)

所以 \(u\) 越往上提能匹配的点越多。

然后剩下未匹配的点在根,按点对间距离从大到小匹配即可。

应该想想就明白了。

有了贪心策略,就可以考虑暴力了。

对于 \(p\),找出子树中所有未匹配的点,对于每个点,查询是否存在 \(dis(u,v)+2\cdot dis(w,p)=dep_u+dep_v-2\cdot dep_p=d\) 的点对,这个可以按深度奇偶分两个 set 简单维护,然后匹配删去即可。复杂度 \(O(n^2\log n)\)

发现可以先枚举 \(dep_u\),显然可能匹配的 \(dep_u\le dep_p+d\),然后用 vector 维护一下 \(V_i\) 即可。复杂度 \(O(nd+n^2\log n)\)

子树中的剩余未匹配点集的信息显然可以先用 dsu on tree 优化。于是优化至 \(O(nd+n\log n)\)

现在瓶颈就在匹配过程中的 \(O(nd)\)

无非就是要找到 \((u,v)\) 满足 \(dep_u+dep_v-2\cdot dep_p\) 直接从 \((u,v)\) 考虑。对于 \((u,v)\) 找到满足条件的 \(dep_p=\frac{dep_u+dep_v}{2}\),将 \((dep_u,dep_v)\) 挂在这个深度上,表示在此深度可以将 \(dep_u\)\(dep_v\) 中的点匹配。可以拿优先队列维护,点 \(u\) 将所有 \(dep_p\ge dep_u\) 的深度对处理了。

贪心的考虑,点 \(u\) 尽量最大的 \(dep_v\) 是优的,根据上文对匹配的限制可得深度最大限制最严,于是每个点只需找到满足 \(dep_u+dep_v-2\cdot dep_w\le d\) 中最大的 \(dep_v\) 形成点对,类似支配对,于是当前点对数就降成 \(O(n)\),而 dsu on tree 的复杂度因为套了个 set 变为 \(O(n\log^2n)\),不过仍能接受。

问题是因为点对间没有保证点不重复,所以会出现深度对 \((dep_u,dep_v)\)\(dep_v\) 中的点已经被其他点全部匹配的情况。那么 \(dep_u\) 就需要同上文再找到当前满足条件的最大的 \(dep_v\),再挂在新的 \(dep_p\) 上(当前子树中无法匹配 \(dep_u\) 提到祖先子树,未匹配点集的信息更多,寻找匹配),将这种情况称作“上提”。

\(dep_u\) 匹配了一次 \(dep_v\),而 \(V_{dep_u}\ne \varnothing\),也需要将 \(dep_u\) 再插入一次,因为深度对是不重的。

void solve(int u){while(dl.size()){if(dl.top().fi<d[u]&&u!=1)return;int d1=dl.top().se,d2=D+2*dl.top().fi-d1;dl.pop();fl[d1].erase(d2);if(d1&1)swap(d1,d2);if(!w[1].count(d2)){auto nx=w[0].upper_bound(d1);if(nx!=w[0].begin())add((--nx)->fi,0,u,1);}if(!w[0].count(d1)){auto ny=w[1].upper_bound(d2);if(ny!=w[1].begin())add((--ny)->fi,0,u,1);}if(!w[0].count(d1)||!w[1].count(d2))continue;int x=w[0][d1].back(),y=w[1][d2].back();w[0][d1].pop_back(),w[1][d2].pop_back();ans.pb(mp(x,y)),vis[x]=vis[y]=1;if(!w[0][d1].size())w[0].erase(d1);if(!w[1][d2].size())w[1].erase(d2);auto nx=w[0].upper_bound(d1),ny=w[1].upper_bound(d2);if(w[0].count(d1)){auto nx=w[0].upper_bound(d1);if(nx!=w[0].begin())add((--nx)->fi,0,u,1);}if(w[1].count(d2)){auto ny=w[1].upper_bound(d2);if(ny!=w[1].begin())add((--ny)->fi,0,u,1);}}
}

然后可以写出这份代码,大部分情况下是优秀的,但是还是能被卡成 \(O(nd)\),因为 \(dep_u\) 对应的深度对可能被上提 \(d\) 次。

64 pts。

考虑问题出在哪。\(dep_u\) 上提后对应的 \(dep_v\) 仍被匹配,继续上提。能否保证 \(dep_u\) 至多上提一次就能找到匹配。

发现深度对匹配的顺序为 \((u,v)\) 按对应的 \(dep_p\) 降序排序。

那么假设深度对 \((u,v)\) 匹配后,\(V_{v}=\varnothing\),那么只需要找到最大的满足 \(\le u\) 的深度对应的深度 \(x\) 对上提即可。

因为对于所有 \((dep,v)\) 的深度对,上提后都是形如 \((dep,y)\) 的深度对,而根据上文对应 \(dep_p\) 的计算式子,显然 \((x,y)\) 对应的 \(dep_p\) 最大,其他的深度对均需要在其匹配之后才有可能匹配。

于是每个深度对匹配后只用上提至多一个深度对,而匹配的总次数 \(\le \lfloor\frac{n}{2}\rfloor\),所以复杂度就优化到 \(O(n\log n+n\log^2 n)\)

100 pts。

#include<bits/stdc++.h>
#define fin(x) freopen(#x".in","r",stdin)
#define fout(x) freopen(#x".out","w",stdout)
#define fr(x) fin(x),fout(x);
#define Fr(x,y) fin(x),fout(y)
#define INPUT(_1,_2,FILE,...) FILE
#define IO(...) INPUT(__VA_ARGS__,Fr,fr)(__VA_ARGS__)
using namespace std;
#define mp make_pair
#define pii pair<int,int>
#define fi first
#define se second
#define pb push_back
#define cfast ios::sync_with_stdio(false);cin.tie(0),cout.tie(0)
#define ll long long
#define ull unsigned long long
#define intz(x,y) memset((x),(y),sizeof((x)))
char *p1,*p2,buf[100000];
#define nc() (p1==p2 && (p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++)
#define tup(x) array<int,(x)>
inline ll read(){ll x=0,f=1;char ch=nc();while(ch<48||ch>57){if(ch=='-')f=-1;ch=nc();}while(ch>=48&&ch<=57)x=x*10+ch-48,ch=nc();return x*f;
}
const int N=5e5+5;
vector<int>e[N];
unordered_map<int,bool>fl[N];
vector<pii>ans;bool vis[N];
int siz[N],d[N],son[N],dfn[N],idx[N],ct,n,D;
priority_queue<pii>dl;
map<int,vector<int> >w[2];
void dfs(int u,int fa){siz[u]=1,d[u]=d[fa]+1;for(int v:e[u])if(v^fa){dfs(v,u),siz[u]+=siz[v];if(siz[v]>siz[son[u]])son[u]=v;}
}
inline void add(int x,int u,int _u,bool flag){auto it=w[!(x&1)].upper_bound(D-x+2*d[_u]);if(it!=w[!(x&1)].begin()){--it;int dep=(x+(it->fi)-D)/2;if(!fl[x].count(it->fi))dl.push(mp(dep,x)),fl[x][it->fi]=1;}if(!flag)w[x&1][x].pb(u);
}
void solve(int u){while(dl.size()){if(dl.top().fi<d[u]&&u!=1)return;int d1=dl.top().se,d2=D+2*dl.top().fi-d1;dl.pop();fl[d1].erase(d2);if(d1&1)swap(d1,d2);if(!w[0].count(d1)||!w[1].count(d2))continue;int x=w[0][d1].back(),y=w[1][d2].back();w[0][d1].pop_back(),w[1][d2].pop_back();ans.pb(mp(x,y)),vis[x]=vis[y]=1;if(!w[0][d1].size())w[0].erase(d1);if(!w[1][d2].size())w[1].erase(d2);auto nx=w[0].upper_bound(d1),ny=w[1].upper_bound(d2);if(nx!=w[0].begin())add((--nx)->fi,0,u,1);if(ny!=w[1].begin())add((--ny)->fi,0,u,1);}
}
void dsu(int u,int fa){idx[dfn[u]=++ct]=u;for(int v:e[u])if((v^fa)&&(v^son[u])){dsu(v,u);for(int i=dfn[v],V=v;i<dfn[v]+siz[v];fl[d[V]].clear(),V=idx[++i]);while(!dl.empty())dl.pop();w[0].clear(),w[1].clear();}if(son[u])dsu(son[u],u);add(d[u],u,u,0);for(int v:e[u])if((v^fa)&&(v^son[u]))for(int i=dfn[v],V=v;i<dfn[v]+siz[v];V=idx[++i])if(!vis[V])add(d[V],V,u,0);solve(u);
}
inline void UesugiErii(){n=read(),D=read();if(D%2==0)--D;for(int i=1,u,v;i<n;i++)u=read(),v=read(),e[u].pb(v),e[v].pb(u);dfs(1,0),dsu(1,0);printf("%d\n",ans.size());for(pii i:ans)printf("%d %d\n",i.fi,i.se);
}
signed main(){//IO();int _=1;//cin>>_;for(;_;_--)UesugiErii();return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/961746.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

重练算法(代码随想录版) day6 - 哈希表part1

day5周日休息一天 今日刷题量:8 当前刷题总量:33 Easy: 20 Mid: 12 Hard: 1 Day 6 基础理论 1.哈希表通常用来判断一个元素是否出现在集合里,牺牲空间来换时间。 2.通过哈希函数得到索引,将元素存储在索引对应的位…

目前广州往返珠海网约车软件

广州往返珠海首选网约车平台推荐:广州城市快线汽车租赁有限公司专业城际出行服务,让您的旅途更舒心如果您正在寻找广州往返珠海的网约车服务,广州城市快线汽车租赁有限公司是您的最佳选择。作为广州地区领先的城际出…

利用RFM模型对客户进行分类

数据大概长这样: A1:C101存储着销售数据 E1:J17对销售数据进行分类汇总以下为单元格公式: F2:用每个客户总消费额,除以每个客户的消费次数,这里次数定义是每人一天算一次 =ROUND(SUMIFS($C:$C,$A:$A,$E2)/SUM(--(U…

第三十七篇

今天是11月10号,上了数据建模语言,Java

别让料单拖慢开关柜生产!这个功能让精准与效率双在线

做成套高低压开关柜的你,是不是常被料单“卡脖子”? 柜型参数记错一个数,采购回来的元件直接报废;找绝缘辅料、断路器型号翻遍多个平台,半天凑不齐一份完整 BOM;好不容易做完料单,采购说型号不对、车间说参数不…

#题解#洛谷P4653

[传送门](P4653 [CEOI 2017] Sure Bet - 洛谷) 分析显然在同一类中选取灯泡越大越好。如果某一类中选取灯泡比另一类比另一类多太多,会造成较大的浪费(每次选灯泡收益-1)于是直觉告诉我们,AB两类的灯泡选取应该尽量…

Netty管道机制:ChannelPipeline与Handler详解

目录1. 简介2. Channel Pipeline的逻辑架构2.1. 通信调度层 Reactor2.2. 职责链 ChannelPipeline2.3. 业务逻辑编排层 ServiceChannelHandler3. ChannelPipeline3.1. ChannelPipeline的类继承关系图3.2. ChannelPipeli…

第六天 svn和git的安装和使用

一、svn的定义:多个人共同开发一个项目,实现共享资源。 作用:对项目相关文件进行管理和共享 (适合近距离,公司内) 二、svn安装 先安装服务端注意事项:将端口修改为8443,创建快捷方式到桌面 服务端的使用 1、创…

华帝热水器维修售后电话24小时—全国各区定点服务中心

华帝热水器(维修)售后服务中心--报修欢迎您 华帝热水器售后电话:400-1819-193 为了更好地为您提供米恩集成灶维修服务,我们特为您整理了详细的报修流程及常见故障处理方法,希望能为您带来便捷的服务体验。如需帮助,…

25.11.10随笔联考总结

考试 正常开题,发现 T1 很简单秒了,看 T2 也很简单,秒了,T3 貌似是一个背包,但是容量很大我一瞬间想到了生成函数然后 Bostan-Mori 直接做,但是又想到这是 NOIP 模拟赛所以放弃多项式小工业(其实我能够写出来)…

[Python刷题记录]-旋转图像-矩阵-中等

[Python刷题记录]-旋转图像-矩阵-中等链接:48. 旋转图像 - 力扣(LeetCode) 解题思路:找到原始点、最终点和中心点之间的关系,以3*3的矩阵为例原始点 最终点 中心点 原始点-中心点 最终点-中心点(1,0) (0,1)…

2025年11月学习机品牌全解析:找准适配款,提分更高效

如今的学习机市场早已进入红海竞争阶段:新品牌层出不穷,老品牌不断推新,各类宣传噱头眼花缭乱 —— 有的标榜 “全科提分神器”,有的宣称 “AI 全能辅导”,甚至不乏夸大功效、混淆概念的 “牛鬼蛇神”,让不少家长…

基于浏览器的DOCX文件编辑器:实现导入、编辑与导出功能 - 实践

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

2025年11月智能油烟机型号排行:实测数据与选购要点一网打尽

站在灶台前,油烟扑面、头发沾味、橱柜黏手,是多数家庭每天面对的“隐形家务”。2025年住建部《住宅厨房空气质量调研》显示,92%的家庭在煎炒高峰期PM2.5瞬时超标三倍,其中30-49岁女性受访者占比68%,她们普遍具备本…

P1531 I Hate It

#include <bits/stdc++.h> using namespace std; #define lc i<<1 #define rc i<<1|1 const int N=2e5+5; int n,m,a[N],ma[N<<2],x,y; void up(int i){ma[i]=max(ma[lc],ma[rc]); } void bu…

CI/CD产品选型调研 - 详解

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

安装向日葵远程协助软件

安装向日葵远程协助软件1、登录网站下载统信uos版向日葵远程控制软件 地址:https://sunlogin.oray.com/download/linux?type=personal下载的deb文件可以直接运行,如果提示因安全问题无法安装时,按提示进入安全设置…

20251110 - KMP

前言 我今天生日!!! 由来 KMP 算法,是由 Knuth、Pratt 和 Morris 三位巨佬发布的一个算法。 他可以在线性(说人话就是 \(O(n + m)\) )时间复杂度内在字符串中查找子串。 思想 朴素算法: 枚举每一个元素,然后从…

个人服务器无法连接外网的设置问题(LINUX,NMCLI)

个人服务器无法连接外网的设置问题(LINUX,NMCLI)本文为和AI大模型KIMI的对话记录,仅供参考。 解决问题,个人迷你主机设置静态地址后,局域网内其他电脑能连接,但是服务器却无法上网,经过查实是网关设置的问题。…

2025年11月智能洗碗机型号推荐榜:麦浪5000plus+领衔全维度对比

把碗留给机器,把时间留给自己,正在成为30-49岁一二线城市品质家庭的共识。白天在写字楼里开完线上会议,晚上回家面对水槽里堆叠的锅碗,很多人第一反应不是“洗”,而是“能不能不洗”。这种“时间焦虑+健康顾虑”的…