树的点分治 bzoj1758【WC2010】重建计划

2024-04-14 23:48

本文主要是介绍树的点分治 bzoj1758【WC2010】重建计划,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

题目大意:
给定一颗树,找到一条路径长度大于等于L,小于等于U。
求满足条件的最大路径平均权值。

题目分析:(树的点分治)
树的点分治入门传送门

上网看了不少题解,路子大致都是:二分+树的点分治+单调队列。
恩恩,道理都懂,但是你不告诉宝宝每一步怎么做像宝宝这种蒟蒻怎么知道怎么写啊掀桌(╯‵□′)╯︵┻━┻,现在写题解的人怎么都这么懒呢QAQ
后来回去看看自己写的其他题解,也都是会的人看了就懂,不会的人看了还是不会,跟没写一样╮(╯ _ ╰)╭好吧那上一段话就当我没说O(∩_∩)O

首先看到所求为一些路径权值的平均数,但是在树分治并不资磁除法,所以可以考虑二分答案。把所有的边权减去二分出来的答案,作为当前边权,检验是否有一个合法的路径满足权值和大于0即可。

检验答案的时候,对于每一分治的根节点,顺序处理它的所有子树,然后合并子树信息。
我们需要维护一个数组代表已搜过的子树中深度为i时的最大权值。
然后对于一个新加入的子树,先搜出这个子树中深度为i时的最大权值,然后和之前的搜过的子树拼接一下,看能拼出来的最大值是否大于等于0。
但是由于路径长度是有范围的,我们可以用一个单调队列维护。

我使用的方法是:
把已经搜过的子树中的点放入单调队列中维护,按照深度从大到小的顺序往里面放。
然后把当前搜索的子树按照深度从小到大扫描一遍,扫到每个点时,判断队列中的深度是否合法,如果队首不合法就弹掉,如果能继续加深度更小的点就加进来,然后更新答案,满足大于等于0的话就直接返回true即可。

还可以考虑一些优化(据说这题卡常?)
每次存最优值的数组不要memset,这个东西常数大,每次用了什么就还原什么。

如果你收到深度大于U的位置就不需要再向下搜了,因为不可能更新答案。

这道题因为要二分,所以可能要做很多次树分治,这样的话我们可以先处理出一个树的重心的序列。然后每次就直接按照这个序列分治就可以。
当然你也可以把二分套在树分治里,这样就不存在这个问题了,但是做法可能会不太一样。

还有一些其他的优化(但是我都没有用=。=),比如说如果分治的点数小于L就不用分了直接返回什么的……

代码如下:

#include <cstdio>
#define N 120000
#define INF 2147483647
using namespace std;
const double EPS=1e-6;
inline double Max(double x,double y) { return x>y?x:y; }
inline int Max(int x,int y) { return x>y?x:y; }
int n,root,sum,rf,L,U;
double l,r,mid;
int fir[N],nes[N<<1],v[N<<1],tot=1;
int xl[N],sz[N],son[N],top;
int dep[N],dl[N];
int maxn;
bool vis[N];
double q[N<<1],dis[N],f[N],fx[N];
void read(int &n)
{n=0;static char ch;while(~(ch=getchar()) && (ch>'9' || ch<'0'));n=ch-'0';while(~(ch=getchar()) && ch<='9' && ch>='0') n=(n<<1)+(n<<3)+(ch-'0');return;
}
void edge(int x,int y,int z)
{tot++;v[tot]=y;q[tot]=(double)z;nes[tot]=fir[x];fir[x]=tot;return;
}
#define edge(x,y,z) edge(x,y,z),edge(y,x,z)
void find_focus(int c,int fa)
{sz[c]=1; son[c]=0;for(int t=fir[c];t;t=nes[t]){if(v[t]==fa || vis[v[t]]) continue;find_focus(v[t],c);sz[c]+=sz[v[t]];if(sz[v[t]]>son[c]) son[c]=sz[v[t]];}if(sum-sz[c]>son[c]) son[c]=sum-sz[c];if(son[c]<son[root]) root=c,rf=fa;return;
}
void get_xl(int c)
{xl[++top]=c; vis[c]=true;for(int t=fir[c];t;t=nes[t]){if(vis[v[t]]) continue;root=0; sum=sz[v[t]];find_focus(v[t],0);sz[rf]=sum-sz[root];get_xl(root);}return;
}
void get_xl()
{root=0; sum=n; son[0]=n;find_focus(1,0);sz[rf]=sum-sz[root];get_xl(root);return;
}
void dfs(int c,int fa)
{dep[c]=dep[fa]+1;if(dep[c]>U) return;fx[dep[c]]=Max(fx[dep[c]],dis[c]);for(int t=fir[c];t;t=nes[t]){if(v[t]==fa || vis[v[t]]) continue;dis[v[t]]=dis[c]+q[t];dfs(v[t],c);}
}
bool solve(int c)
{vis[c]=true;int now=0;bool judge=false;for(int t=fir[c];t;t=nes[t]){if(vis[v[t]]) continue;dis[v[t]]=q[t];dfs(v[t],0);int l=1,r=1; dl[1]=0;for(int i=1;fx[i]!=-INF;i++){while(now>0 && now-1+i>=L){now--;while(f[now]>=f[dl[r]] && r>=l) r--;dl[++r]=now;}while(dl[l]+i>U) l++;if(fx[i]+f[dl[l]]>=0) {judge=true;break;}}int i;for(i=1;fx[i]!=-INF;i++)f[i]=Max(f[i],fx[i]),fx[i]=-INF;now=Max(now,i);if(judge) break;}while(now--) f[now]=-INF;return judge;
}
bool check()
{bool judge=false;int i;for(i=2;i<=tot;i++) q[i]-=mid;for(i=1;i<=top;i++)if(solve(xl[i])) { judge=true; break; }while(i--) vis[i]=false;for(i=2;i<=tot;i++) q[i]+=mid;return judge;
}
int main()
{read(n); read(L); read(U);for(int i=1,x,y,z;i<n;i++){read(x);read(y);read(z);edge(x,y,z);maxn=Max(maxn,z);}get_xl();for(int i=0;i<=n+1;i++) f[i]=fx[i]=-INF,vis[i]=false;f[0]=0;l=0,r=maxn;while(r-l>=EPS){mid=(l+r)/2.0;if(check()) l=mid;else r=mid;}printf("%.3lf\n",l);return 0;}

这篇关于树的点分治 bzoj1758【WC2010】重建计划的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/904364

相关文章

Codeforces Round #240 (Div. 2) E分治算法探究1

Codeforces Round #240 (Div. 2) E  http://codeforces.com/contest/415/problem/E 2^n个数,每次操作将其分成2^q份,对于每一份内部的数进行翻转(逆序),每次操作完后输出操作后新序列的逆序对数。 图一:  划分子问题。 图二: 分而治之,=>  合并 。 图三: 回溯:

《计算机视觉工程师养成计划》 ·数字图像处理·数字图像处理特征·概述~

1 定义         从哲学角度看:特征是从事物当中抽象出来用于区别其他类别事物的属性集合,图像特征则是从图像中抽取出来用于区别其他类别图像的属性集合。         从获取方式看:图像特征是通过对图像进行测量或借助算法计算得到的一组表达特性集合的向量。 2 认识         有些特征是视觉直观感受到的自然特征,例如亮度、边缘轮廓、纹理、色彩等。         有些特征需要通

Claude Enterprise推出计划

每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗?订阅我们的简报,深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同,从行业内部的深度分析和实用指南中受益。不要错过这个机会,成为AI领域的领跑者。点击订阅,与未来同行! 订阅:https://rengongzhineng.io/ 今天推出的Claude Enterprise计划,专为企业打造安全的

为备份驱动器制定备份计划:维护数据的3大方法

时间:2014-02-26 14:49 来源:网管之家 字体:[大 中 小]   您可能已经对您的电脑进行了备份,但其实这样还是远远不够的,其并非如您所认为的那样安全。您企业备份驱动器上的文件可能与您的主系统上的文件一样,容易受到灾难的影响。根据最近流行的恶意软件CryptoLocker的感染途径显示,连接到PC的外置驱动器——辅助硬盘驱动器,例如,用于备份的外部USB硬盘驱动器,可以像

基于开源链动 2 + 1 模式、AI 智能名片与 S2B2C 商城小程序的用户忠诚度计划

摘要:本文深入探讨了在商业环境中执行用户忠诚度计划的创新途径。通过整合开源链动 2 + 1 模式、AI 智能名片以及 S2B2C 商城小程序等先进元素,从提供福利、解决问题和创造赚钱机会三个核心方面展开详细阐述。研究表明,这些新技术和新模式的有机结合,能够为企业打造更具吸引力和影响力的用户忠诚度计划,从而实现商业效益的最大化与可持续发展。 一、引言 在当今竞争激烈且市场环境快速变化的时代,

[置顶] 2014训练计划进阶版

动态规划: 区间dp,树状dp,数位dphdu3555, sgu258, sgu390  队列优化: zoj3399 最小表示法的状态压缩DP: spoj2159  专题链接:http://acm.hust.edu.cn/vjudge/contest/view.action?cid=38881#overview 专题链接: http://acm.hust.edu.cn/vjudg

[置顶] 2014训练计划

每个专题结束后会有5小时的专题赛~ 1、hustOJ目前支持谷歌、火狐浏览器等部分浏览器。 2、欢迎吐槽~ 3、推荐该阶段用书(以下具体算法实现多数可在此书中找到详解):算法竞赛入门经典之训练指南(刘汝佳) 4、题解报告:专题中的题目多是经典题目,百度搜索即有详细解答~ 5、专题相关知识点红字标出,建议先百度红字部分,有助于专题学习~ 6、专题时间会在"ACM 今天你AC了吗?"(12

Windows 一键定时自动化任务神器 zTasker,支持语音报时+多项定时计划执行

简介 zTasker(详情请戳 官网)是一款完全免费支持定时、热键或条件触发的方式执行多种自动化任务的小工具,支持win7-11。其支持超过100种任务类型,50+种定时/条件执行方法,而且任务列表可以随意编辑、排列、移动、更改类型,支持任务执行日志,可覆盖win自带的热键,同时支持任务列表等数据的备份及自动更新等。 简言之,比微软系统自带的任务计划要强好几倍,至少灵活性高多了,能大幅提高电脑使

【Oracle篇】全面理解优化器和SQL语句的解析步骤(含执行计划的详细分析和四种查看方式)(第二篇,总共七篇)

💫《博主介绍》:✨又是一天没白过,我是奈斯,DBA一名✨ 💫《擅长领域》:✌️擅长Oracle、MySQL、SQLserver、阿里云AnalyticDB for MySQL(分布式数据仓库)、Linux,也在扩展大数据方向的知识面✌️ 💖💖💖大佬们都喜欢静静的看文章,并且也会默默的点赞收藏加关注💖💖💖 SQL优化续新篇,第二篇章启幕时。 优化器内藏奥秘,解析SQL步