博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
luogu题解 P1099 【树网的核】树的直径变式+数据结构维护
阅读量:5280 次
发布时间:2019-06-14

本文共 2717 字,大约阅读时间需要 9 分钟。

  • 题目链接:

    (加强版)

  • 分析:

    首先你需要\(O(N)\)求树的直径的前置技能,其实很简单,先随便找个根找到树上距离它最远的顶点\(S\),然后以\(S\)为根找树上距离\(S\)最远的顶点\(E\),\(S,E\)之间的路径就是树的直径

    1. 暴力枚举

      按照题目要求说的去做就好了,求出树的直径,然后根据贪心找长度小于等于s的路径搜一遍就好了,时间复杂度\(O(N^2)\) 代码难度小 可过NOIP数据

    2. 预处理扫描

      还是先求出树的直径,然后通过仔细分析偏心距怎么求,发现无非三种情况

      1.直径最左端顶点到路径最左端顶点距离

      2.路径上各点不经过直径上其他点到达的最大距离

      3.直径上最右端顶点到路径最右端顶点的距离

      我相信2理解不难,现在简单证明1情况(3同理)的正确性:假设路径最左端有一条向左延伸的路径其终点\(E'\)不是直径左端点而距离却更大,则违反直径定义,因为这样\(E'\)与路径左端点连接能形成一条更长的直径

      于是我们需要四遍DFS(也许你写的好的话并不需要这么多遍)

      前两遍就是求树的直径,用一个\(dmet[]\)将直径各点按顺序记录方便区间处理,\(diameter\)为直径长度

      第三遍求直径上各点不经过直径上其他点达到的最大距离,用\(d[]\)记录

      第四遍求直径左右段点到直径各点距离,用\(ld[],rd[]\)记录

      然后我们扫描长度小于等于s的路径(可能是一个点),找上述三种情况的最大值,找第二种情况最大值你可以用滑动窗口,ST Table,线段树在区间查找最大值,这里采用线段树

      时间复杂度:\(O(N\log N)\)

      可以过比较大的数据,这是加强版

  • 代码

    写得比较丑,见谅

#include 
#include
#include
#include
#include
#include
#include
#define ll long long #define ri register int using namespace std;const int maxn=500005;const int maxm=1000005;const int inf=0x7fffffff;template
inline void read(T &x){ x=0;int ne=0;char c; while(!isdigit(c=getchar()))ne=c=='-'; x=c-48; while(isdigit(c=getchar()))x=(x<<3)+(x<<1)+c-48; x=ne?-x:x; return ;}struct Edge{ int ne,to,dis;}edge[maxm];int h[maxn],num_edge=0,mx=-inf;bool vis[maxn];void add(int f,int to,int dis){ edge[++num_edge].ne=h[f]; edge[num_edge].to=to; edge[num_edge].dis=dis; h[f]=num_edge;}int n,s,head,tail;void dfs_1(int fa,int cur,int cnt){ for(ri i=h[cur];i;i=edge[i].ne){ if(edge[i].to!=fa)dfs_1(cur,edge[i].to,cnt+edge[i].dis); } if(cnt>mx){ mx=cnt,head=cur; } return ;}int pre[maxn],dmet[maxn],d[maxn],diameter;void dfs_2(int fa,int cur,int cnt){ for(ri i=h[cur];i;i=edge[i].ne){ if(edge[i].to!=fa){ pre[edge[i].to]=cur; dfs_2(cur,edge[i].to,cnt+edge[i].dis); } } if(cnt>mx){ mx=cnt,tail=cur; } return ;}int root;void dfs_3(int fa,int cur,int cnt){ for(ri i=h[cur];i;i=edge[i].ne){ int v=edge[i].to; if(!vis[v]&&v!=fa){ dfs_3(cur,v,cnt+edge[i].dis); } } if(cnt>mx){ mx=cnt,d[root]=cnt; } return ;}int ld[maxn],rd[maxn],fun[maxn];void dfs_4(int fa,int cur,int cnt){ for(ri i=h[cur];i;i=edge[i].ne){ int v=edge[i].to; if(vis[v]&&v!=fa){ dfs_4(cur,v,cnt+edge[i].dis); } } ld[fun[cur]]=cnt,rd[fun[cur]]=diameter-cnt; return ;}int maxx[maxn<<2],L,R;void build(int now,int l,int r){ if(l==r){ maxx[now]=d[dmet[l]]; return; } int mid=(l+r)>>1; build(now<<1,l,mid); build(now<<1|1,mid+1,r); maxx[now]=max(maxx[now<<1],maxx[now<<1|1]); return ;}int query(int now,int l,int r){ if(L<=l&&r<=R){ return maxx[now]; } int mid=(l+r)>>1,ans=-inf; if(L<=mid)ans=max(ans,query(now<<1,l,mid)); if(mid
<<1|1,mid+1,r)); return ans;}int main(){ int x,y,z; read(n),read(s); for(ri i=1;i

转载于:https://www.cnblogs.com/Rye-Catcher/p/9248789.html

你可能感兴趣的文章
JavaScript中随着鼠标拖拽而移动的块
查看>>
HDU 1021 一道水题
查看>>
The operation couldn’t be completed. (LaunchServicesError error 0.)
查看>>
php每天一题:strlen()与mb_strlen()的作用分别是什么
查看>>
工作中收集JSCRIPT代码之(下拉框篇)
查看>>
《转载》POI导出excel日期格式
查看>>
code异常处理
查看>>
git - 搭建最简单的git server
查看>>
会话控制
查看>>
推荐一款UI设计软件Balsamiq Mockups
查看>>
Linux crontab 命令格式与详细例子
查看>>
百度地图Api进阶教程-地图鼠标左右键操作实例和鼠标样式6.html
查看>>
游标使用
查看>>
LLBL Gen Pro 设计器使用指南
查看>>
SetCapture() & ReleaseCapture() 捕获窗口外的【松开左键事件】: WM_LBUTTONUP
查看>>
Android 设置界面的圆角选项
查看>>
百度地图api服务端根据经纬度得到地址
查看>>
CSS中隐藏内容的3种方法及属性值
查看>>
每天一个linux命令(1):ls命令
查看>>
根据xml生成相应的对象类
查看>>