题目大意:给你一颗环套树,你要在这棵的边上(包括端点)找一个点,使得离该点最远的点最近。

数据范围:$n≤10^5$,边权$≤10^9$。

此题不难看出一种暴力做法,我们依次断开环上的一条边,然后求整颗树的直径,取个$min$就好了,时间复杂度是$O(n^2)$的。

然而显然会$T$,我们考虑一些优秀的做法,我们首先将环拆成链,将链倍长(通用套路),然后将环上的点重新编号一下,设环上点的个数为$m$。

如果我们去掉了这个环,原图会变成森林,对于森林中的每一棵树,我们都先求一下它的直径。

令$D_i$表示以环上第$i$个点为根的子树内,与$i$号点距离最大的点与$i$号点间的距离。

令$S_i$表示环上第$i$个点距离环上第一个点的距离(此处的i可以从$1$取到$2m$)。

那么,对于环上两点$(i,j)$,由$i$为根子树,$j$为根子树,还有i至j的链构成的树的直径为$D_i+D_j-S_i+S_j$。

移项后有$(D_i-S_i)+(D_j+S_j)$。

我们用线段树维护这个东西就可以了,(我的线段树写得有点挫,应该有更高效的编码方法)

 #include<bits/stdc++.h>
#define M 200005
#define L long long
#define INF (1LL<<60)
#define mid ((a[x].l+a[x].r)/2)
using namespace std; struct edge{L u,v,next;}e[M*]={}; L head[M]={},use=;
void add(L x,L y,L z){use++;e[use].u=y;e[use].v=z;e[use].next=head[x];head[x]=use;} struct node{L l,r;L tag,tag2,mx,mx2,ans;}a[M<<]={};
void build(L x,L l,L r){
a[x].l=l; a[x].r=r; a[x].ans=a[x].mx=a[x].mx2=-INF; if(l==r) return;
build(x<<,l,mid); build(x<<|,mid+,r);
}
void upd(L x,L k){
a[x].tag+=k; a[x].mx+=k;
if(a[x].l!=a[x].r) a[x].ans=max(max(a[x<<].mx+a[x<<|].mx2,a[x<<].mx2+a[x<<|].mx),max(a[x<<].ans,a[x<<|].ans));
}
void upd2(L x,L k){
a[x].tag2+=k; a[x].mx2+=k;
if(a[x].l!=a[x].r) a[x].ans=max(max(a[x<<].mx+a[x<<|].mx2,a[x<<].mx2+a[x<<|].mx),max(a[x<<].ans,a[x<<|].ans));
}
void pushdown(L x){
if(a[x].tag!=) upd(x<<,a[x].tag),upd(x<<|,a[x].tag); a[x].tag=;
if(a[x].tag2!=) upd2(x<<,a[x].tag2),upd2(x<<|,a[x].tag2); a[x].tag2=;
}
void pushup(L x){
a[x].mx=max(a[x<<].mx,a[x<<|].mx);
a[x].mx2=max(a[x<<].mx2,a[x<<|].mx2);
a[x].ans=max(max(a[x<<].mx+a[x<<|].mx2,a[x<<].mx2+a[x<<|].mx),max(a[x<<].ans,a[x<<|].ans));
}
void updata(L x,L l,L r,L k){
if(l<=a[x].l&&a[x].r<=r) return upd(x,k);
pushdown(x);
if(l<=mid) updata(x<<,l,r,k);
if(mid<r) updata(x<<|,l,r,k);
pushup(x);
}
void updata(L x,L k,L val){
if(a[x].l==a[x].r){a[x].tag=; a[x].mx=val; return;}
pushdown(x);
if(k<=mid) updata(x<<,k,val);
else updata(x<<|,k,val);
pushup(x);
}
void updata2(L x,L l,L r,L k){
if(l<=a[x].l&&a[x].r<=r) return upd2(x,k);
pushdown(x);
if(l<=mid) updata2(x<<,l,r,k);
if(mid<r) updata2(x<<|,l,r,k);
pushup(x);
}
void updata2(L x,L k,L val){
if(a[x].l==a[x].r){a[x].tag2=; a[x].mx2=val; return;}
pushdown(x);
if(k<=mid) updata2(x<<,k,val);
else updata2(x<<|,k,val);
pushup(x);
} L cir[M]={},vis[M]={},n,m=; stack<int> st;
bool getcir(L x,L fa){
if(vis[x]){
for(L now=st.top();now!=x;st.pop(),now=st.top()){
cir[++m]=now;
}
cir[++m]=x;
return ;
}
st.push(x); vis[x]=;
for(L i=head[x];i;i=e[i].next) if(e[i].u!=fa){
if(getcir(e[i].u,x)) return ;
}
st.pop();
return ;
} void init(){
scanf("%lld",&n);
for(L i=;i<=n;i++){
L x,y,z; scanf("%lld%lld%lld",&x,&y,&z);
add(x,y,z); add(y,x,z);
}
} L d[M]={},s[M]={},ans=;
L dfs(L x,L fa){
L max1=,max2=;
for(L i=head[x];i;i=e[i].next) if(e[i].u!=fa){
L k=dfs(e[i].u,x)+e[i].v;
if(k>max1) max2=max1,max1=k;
else if(k>max2) max2=k;
}
ans=max(ans,max1+max2);
return max1;
}
void getmax(){
for(L x=;x<=m;x++) cir[x+m]=cir[x];
cir[]=cir[m]; cir[m*+]=cir[];
for(L x=;x<=m;x++){
L max1=,max2=;
for(L i=head[cir[x]];i;i=e[i].next)
if(e[i].u!=cir[x-]&&e[i].u!=cir[x+]){
L k=dfs(e[i].u,cir[x])+e[i].v;
if(k>max1) max2=max1,max1=k;
else if(k>max2) max2=k;
}
ans=max(ans,max1+max2);
d[x]=max1;
} for(L x=;x<=*m;x++){
L u=cir[x];
for(L i=head[u];i;i=e[i].next)
if(e[i].u==cir[x+]) s[x]=e[i].v;
}
} void work(){
L minn=,S=;
for(L i=;i<=m;i++){
S+=s[i-];
updata2(,i,S+d[i]);
minn=max(minn,a[].ans);
updata(,i,d[i]-S);
}
for(L i=;i<=m;i++){
updata(,,m,s[i]);
updata(,i,-INF);
updata2(,,m,-s[i]);
updata2(,i,-INF);
S-=s[i];
S+=s[i+m-];
updata2(,i,S+d[i]);
minn=min(minn,a[].ans);
updata(,i,d[i]-S);
}
ans=max(ans,minn);
} main(){
init();
getcir(,);
build(,,m);
getmax();
work();
double hh=ans; hh/=;
printf("%.1lf\n",hh);
}

【NOI2013】快餐店 环套树+线段树的更多相关文章

  1. 浅谈树套树(线段树套平衡树)&学习笔记

    0XFF 前言 *如果本文有不好的地方,请在下方评论区提出,Qiuly感激不尽! 0X1F 这个东西有啥用? 树套树------线段树套平衡树,可以用于解决待修改区间\(K\)大的问题,当然也可以用 ...

  2. 【BZOJ-3306】树 线段树 + DFS序

    3306: 树 Time Limit: 10 Sec  Memory Limit: 256 MBSubmit: 792  Solved: 262[Submit][Status][Discuss] De ...

  3. BZOJ_3196_二逼平衡树_(树套树,线段树+Treap)

    描述 http://www.lydsy.com/JudgeOnline/problem.php?id=3196 可以处理区间问题的平衡树. 3196: Tyvj 1730 二逼平衡树 Time Lim ...

  4. Bzoj 1901: Zju2112 Dynamic Rankings 树套树,线段树,平衡树,Treap

    1901: Zju2112 Dynamic Rankings Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 6471  Solved: 2697[Su ...

  5. [BZOJ 1901] Dynamic Rankings 【树状数组套线段树 || 线段树套线段树】

    题目链接:BZOJ - 1901 题目分析 树状数组套线段树或线段树套线段树都可以解决这道题. 第一层是区间,第二层是权值. 空间复杂度和时间复杂度均为 O(n log^2 n). 线段树比树状数组麻 ...

  6. BZOJ 3685: 普通van Emde Boas树( 线段树 )

    建颗权值线段树就行了...连离散化都不用... 没加读入优化就TLE, 加了就A掉了...而且还快了接近1/4.... ---------------------------------------- ...

  7. LOJ#3043.【ZJOI2019】 线段树 线段树,概率期望

    原文链接www.cnblogs.com/zhouzhendong/p/ZJOI2019Day1T2.html 前言 在LOJ交了一下我的代码,发现它比选手机快将近 4 倍. 题解 对于线段树上每一个节 ...

  8. poj 2155 matrix 二维线段树 线段树套线段树

    题意 一个$n*n$矩阵,初始全为0,每次翻转一个子矩阵,然后单点查找 题解 任意一种能维护二维平面的数据结构都可以 我这里写的是二维线段树,因为四分树的写法复杂度可能会退化,因此考虑用树套树实现二维 ...

  9. cf842D 01字典树|线段树 模板见hdu4825

    一般异或问题都可以转换成字典树的问题,,我一开始的想法有点小问题,改一下就好了 下面的代码是逆向建树的,数据量大就不行 /*3 01字典树 根据异或性质,a1!=a2 ==> a1^x1^..^ ...

随机推荐

  1. Shell获取当前路径

    PRG="$0" while [ -h "$PRG" ]; do ls=`ls -ld "$PRG"` link=`expr "$ ...

  2. Win7 SP1 提示ADO的问题

    需要安装  Windows6.1-KB2640696-v3-x64.msu 这个Pack

  3. VHDL实例化过程

    第二步:建立一个名为MUX_0的乘法器 第三步:在程序中例化,看以下程序. -- 该程序用来实现复数的乘法,端口分别定义的复数的 -- 输入的实部和虚部和输出的实部和虚部 LIBRARY IEEE; ...

  4. 在 Java 中使用 protobuf

    在 Java 中使用 protobuf 从 https://github.com/google/protobuf/releases 下载编译器,并设置环境变量. 创建java项目添加protobuf- ...

  5. (匹配 匈牙利)棋盘游戏 -- Hdu --1281

    链接: http://acm.hdu.edu.cn/showproblem.php?pid=1281 http://acm.hust.edu.cn/vjudge/contest/view.action ...

  6. Javascript 中函数的 length 属性

    每个函数都有一个 length属性 (函数名.length), 表示期望接收的函数的个数(而不是实际接收的参数个数) 它与arguments不同. arguments.length 是表示函数实际接收 ...

  7. HDU1237 简单计算器 2016-07-24 13:34 193人阅读 评论(0) 收藏

    简单计算器 Problem Description 读入一个只包含 +, -, *, / 的非负整数计算表达式,计算该表达式的值. Input 测试输入包含若干测试用例,每个测试用例占一行,每行不超过 ...

  8. POJ1556 最短路 + 线段相交问题

    POJ1556 题目大意:比较明显的题目,在一个房间中有几堵墙,直着走,问你从(0,5)到(10,5)的最短路是多少 求最短路问题,唯一变化的就是边的获取,需要我们获取边,这就需要判断我们想要走的这条 ...

  9. Android App 退出整个应用

    在做Android APP 过程中,有退出整个Project的功能,以下就是接受退出整个应用的操作: ActivityManager是用来管理记录每一个Activity,最后统一用来退出结束: pub ...

  10. Visual Studio模板

    转载自MSDN,此文仅作参考. http://msdn.microsoft.com/zh-cn/library/6db0hwky(VS.80).aspx 1. 如何导入“项目模板(Project Te ...