毒瘤,毒瘤,毒瘤……

\(30000\)这个数据范围,看上去就是要搞事的啊。。。

题目链接: https://www.lydsy.com/JudgeOnline/problem.php?id=2402

题解:

首先化式子: 假设二分的答案为\(mid\)则\(\frac{y_i+q_j}{x_i+p_j}\ge mid, y_i+q_j\ge mid(x_i+p_j), y_i-mid\times x_i+q_j-mid\times p_j\ge 0\)

那么我们实际上就是要找一个\(i\)使得\(-x_i\times mid+y_i\)最大,同理找一个\(j\)使得\(-p_j\times mid+q_j\)最大,这两个任务完全一样,现在就讨论前者

为了方便(强迫症)让我们把它变成\(-a_ix+b_i\)的形式

仿照斜率优化的思路,如果\(a_i<a_j\),那么\(i\)不劣于\(j\)当且仅当\(-a_ix+b_i\ge -a_jx+b_j, x\ge \frac{b_j-b_i}{a_j-a_i}\).

那么假设有并排着的三个点\(i,j,k,a_i<a_j<a_k\), 则\(i\)不劣于\(j\)当且仅当\(x\ge \frac{b_j-b_i}{a_j-a_i}\), \(k\)不劣于\(j\)当且仅当\(x\le \frac{b_k-b_j}{a_k-a_j}\), 如果\(\frac{b_j-b_i}{a_j-a_i}\le \frac{b_k-b_j}{a_k-a_j}\), 那么对于任何\(x\)上面两个条件至少有一个成立,那么\(j\)就是无用的。也就是说有用的点一定满足斜率递减,在上凸壳的左半边上。

这题没有修改操作,那么我们可以用线段树求出每个子区间内的凸壳,然后对于每个询问,先分数规划二分答案,然后求树链剖分划分成的每一段区间的最大值,这个可以通过在线段树每个子区间的凸壳上二分得到。

时间复杂度\(O(n\log^4n)\)

(这可能是我最近写的几道题唯一一道跑进BZOJ前一半的?23333)

代码

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cassert>
#include<vector>
using namespace std; const int N = 3e4;
const double EPS = 1e-8;
const double INF = 1e6;
int dcmp(double x) {return x<-EPS ? -1 : (x>EPS ? 1 : 0);}
struct Point
{
double x,y;
Point() {}
Point(double _x,double _y) {x = _x,y = _y;}
bool operator <(const Point &arg) const {return dcmp(x-arg.x)<0 || (dcmp(x-arg.x)==0 && dcmp(y-arg.y)<0);}
};
struct Edge
{
int v,w,nxt;
} e[(N<<1)+3];
int fe[N+3];
int fa[N+3];
int dfn[N+3];
int idfn[N+3];
int sz[N+3];
int tpn[N+3];
int dep[N+3];
int hvs[N+3];
double a1[N+3],b1[N+3],a2[N+3],b2[N+3];
int n,q,en,cnt; struct SegmentTree
{
vector<Point> sgt[(N<<2)+3];
void CHpush(int id,Point x)
{
int j = sgt[id].size()-1;
while(j>0 && dcmp((sgt[id][j].y-sgt[id][j-1].y)*(x.x-sgt[id][j].x)-(sgt[id][j].x-sgt[id][j-1].x)*(x.y-sgt[id][j].y))<=0)
{
sgt[id].pop_back();
j--;
}
sgt[id].push_back(x);
}
void build(int rtn,int le,int ri,double a[],double b[])
{
if(le==ri)
{
sgt[rtn].push_back(Point(a[idfn[le]],b[idfn[le]]));
return;
}
int mid = (le+ri)>>1;
build(rtn<<1,le,mid,a,b);
build(rtn<<1|1,mid+1,ri,a,b);
int i = 0,j = 0;
while(i<sgt[rtn<<1].size() && j<sgt[rtn<<1|1].size())
{
if(sgt[rtn<<1][i]<sgt[rtn<<1|1][j]) {CHpush(rtn,sgt[rtn<<1][i]); i++;}
else {CHpush(rtn,sgt[rtn<<1|1][j]); j++;}
}
while(i<sgt[rtn<<1].size()) {CHpush(rtn,sgt[rtn<<1][i]); i++;}
while(j<sgt[rtn<<1|1].size()) {CHpush(rtn,sgt[rtn<<1|1][j]); j++;}
}
double calc(int rtn,double x)
{
int left = 0,right = sgt[rtn].size()-1;
while(left<right)
{
int mid = (left+right+1)>>1;
if(mid==0) {break;}
if(dcmp(x*(sgt[rtn][mid].x-sgt[rtn][mid-1].x)-(sgt[rtn][mid].y-sgt[rtn][mid-1].y))<=0) {left = mid;}
else {right = mid-1;}
}
double ret = -sgt[rtn][left].x*x+sgt[rtn][left].y;
return ret;
}
double query(int rtn,int le,int ri,int lb,int rb,double x)
{
if(le>=lb && ri<=rb) {return calc(rtn,x);}
int mid = (le+ri)>>1; double ret = -INF;
if(lb<=mid) {ret = max(ret,query(rtn<<1,le,mid,lb,rb,x));}
if(rb>mid) {ret = max(ret,query(rtn<<1|1,mid+1,ri,lb,rb,x));}
return ret;
}
} sgt1,sgt2; void addedge(int u,int v)
{
en++; e[en].v = v;
e[en].nxt = fe[u]; fe[u] = en;
} void dfs1(int u)
{
sz[u] = 1; hvs[u] = 0;
for(int i=fe[u]; i; i=e[i].nxt)
{
int v = e[i].v;
if(v==fa[u]) continue;
fa[v] = u;
dep[v] = dep[u]+1;
dfs1(v);
sz[u] += sz[v];
if(sz[v]>sz[hvs[u]]) {hvs[u] = v;}
}
} void dfs2(int u)
{
cnt++; dfn[u] = cnt; idfn[cnt] = u;
if(hvs[u]) {tpn[hvs[u]] = tpn[u]; dfs2(hvs[u]);}
for(int i=fe[u]; i; i=e[i].nxt)
{
int v = e[i].v;
if(v==hvs[u] || v==fa[u]) continue;
tpn[v] = v;
dfs2(v);
}
} bool query(int u,int v,double x)
{
double ret1 = -INF,ret2 = -INF;
while(tpn[u]!=tpn[v])
{
if(dep[fa[tpn[u]]]>dep[fa[tpn[v]]])
{
double tmp = sgt1.query(1,1,n,dfn[tpn[u]],dfn[u],x);
ret1 = max(ret1,tmp);
tmp = sgt2.query(1,1,n,dfn[tpn[u]],dfn[u],x);
ret2 = max(ret2,tmp);
u = fa[tpn[u]];
}
else
{
double tmp = sgt1.query(1,1,n,dfn[tpn[v]],dfn[v],x);
ret1 = max(ret1,tmp);
tmp = sgt2.query(1,1,n,dfn[tpn[v]],dfn[v],x);
ret2 = max(ret2,tmp);
v = fa[tpn[v]];
}
}
if(dep[u]>dep[v]) swap(u,v);
double tmp = sgt1.query(1,1,n,dfn[u],dfn[v],x);
ret1 = max(ret1,tmp);
tmp = sgt2.query(1,1,n,dfn[u],dfn[v],x);
ret2 = max(ret2,tmp);
if(dcmp(ret1+ret2)>0) return true;
return false;
} int main()
{
scanf("%d",&n);
for(int i=1; i<=n; i++) scanf("%lf",&a1[i]);
for(int i=1; i<=n; i++) scanf("%lf",&b1[i]);
for(int i=1; i<=n; i++) scanf("%lf",&a2[i]);
for(int i=1; i<=n; i++) scanf("%lf",&b2[i]);
for(int i=1; i<n; i++)
{
int x,y; scanf("%d%d",&x,&y);
addedge(x,y); addedge(y,x);
}
dep[1] = 1; dfs1(1);
tpn[1] = 1; dfs2(1);
sgt1.build(1,1,n,a1,b1);
sgt2.build(1,1,n,a2,b2);
scanf("%d",&q);
for(int i=1; i<=q; i++)
{
int x,y; scanf("%d%d",&x,&y);
double left = 0.0,right = 1e5;
while(right-left>5e-5)
{
double mid = (left+right)*0.5;
bool ans = query(x,y,mid);
if(ans) {left = mid;}
else {right = mid;}
}
printf("%lf\n",left);
}
return 0;
}

BZOJ 2402 陶陶的难题II (树链剖分、线段树、凸包、分数规划)的更多相关文章

  1. BZOJ 3672[NOI2014]购票(树链剖分+线段树维护凸包+斜率优化) + BZOJ 2402 陶陶的难题II (树链剖分+线段树维护凸包+分数规划+斜率优化)

    前言 刚开始看着两道题感觉头皮发麻,后来看看题解,发现挺好理解,只是代码有点长. BZOJ 3672[NOI2014]购票 中文题面,题意略: BZOJ 3672[NOI2014]购票 设f(i)f( ...

  2. 【bzoj2402】陶陶的难题II 分数规划+树链剖分+线段树+STL-vector+凸包+二分

    题目描述 输入 第一行包含一个正整数N,表示树中结点的个数.第二行包含N个正实数,第i个数表示xi (1<=xi<=10^5).第三行包含N个正实数,第i个数表示yi (1<=yi& ...

  3. BZOJ.4034 [HAOI2015]树上操作 ( 点权树链剖分 线段树 )

    BZOJ.4034 [HAOI2015]树上操作 ( 点权树链剖分 线段树 ) 题意分析 有一棵点数为 N 的树,以点 1 为根,且树点有边权.然后有 M 个 操作,分为三种: 操作 1 :把某个节点 ...

  4. BZOJ.1036 [ZJOI2008]树的统计Count ( 点权树链剖分 线段树维护和与最值)

    BZOJ.1036 [ZJOI2008]树的统计Count (树链剖分 线段树维护和与最值) 题意分析 (题目图片来自于 这里) 第一道树链剖分的题目,谈一下自己的理解. 树链剖分能解决的问题是,题目 ...

  5. bzoj 4196 [Noi2015]软件包管理器 (树链剖分+线段树)

    4196: [Noi2015]软件包管理器 Time Limit: 10 Sec  Memory Limit: 512 MBSubmit: 2852  Solved: 1668[Submit][Sta ...

  6. bzoj 2157: 旅游【树链剖分+线段树】

    裸的树链剖分+线段树 但是要注意一个地方--我WA了好几次才发现取完相反数之后max值和min值是要交换的-- #include<iostream> #include<cstdio& ...

  7. BZOJ 3589 动态树 (树链剖分+线段树)

    前言 众所周知,90%90\%90%的题目与解法毫无关系. 题意 有一棵有根树,两种操作.一种是子树内每一个点的权值加上一个同一个数,另一种是查询多条路径的并的点权之和. 分析 很容易看出是树链剖分+ ...

  8. 【bzoj1959】[Ahoi2005]LANE 航线规划 树链剖分+线段树

    题目描述 对Samuel星球的探险已经取得了非常巨大的成就,于是科学家们将目光投向了Samuel星球所在的星系——一个巨大的由千百万星球构成的Samuel星系. 星际空间站的Samuel II巨型计算 ...

  9. 【BZOJ-2325】道馆之战 树链剖分 + 线段树

    2325: [ZJOI2011]道馆之战 Time Limit: 40 Sec  Memory Limit: 256 MBSubmit: 1153  Solved: 421[Submit][Statu ...

  10. 【BZOJ2243】[SDOI2011]染色 树链剖分+线段树

    [BZOJ2243][SDOI2011]染色 Description 给定一棵有n个节点的无根树和m个操作,操作有2类: 1.将节点a到节点b路径上所有点都染成颜色c: 2.询问节点a到节点b路径上的 ...

随机推荐

  1. Fiddler 抓包工具详解

    Fiddler是一个蛮好用的抓包工具,可以将网络传输发送与接受的数据包进行截获.重发.编辑.转存等操作.也可以用来检测网络安全.反正好处多多,举之不尽呀!当年学习的时候也蛮费劲,一些蛮实用隐藏的小功能 ...

  2. 彭博社:博通正在与赛门铁克洽谈收购事宜(博通能买得起 又能讲故事的 没几个了 为了刺激资本的兴趣 只能瞎搞 就和intel 收购 麦咖啡一样。就像杜蕾斯收购美赞臣一样,也许只是纯粹的商业行为,哪行赚钱干哪行)

    彭博社今日消息,知名芯片制造商 Broadcom 公司正在就收购网络安全公司 Symantec 事宜进行高级会谈,因为 Broadcom 希望寻找半导体业务之外的机会,以实现多元化经营. 据称,在彭博 ...

  3. 怎样查看或修改元素节点的id属性

    使用 el.id; el表示获取到的元素节点, 如下所示: // HTML 代码 // <div id="app" class="c1">hello ...

  4. Oracle 分页语句

    ** 写法1 :采用 ROWNUM的伪列: --查询10到20之间的数据 -- SELECT * FORM ( -- SELECT * , ROWNUM rn FROM TABLE_NAME -- W ...

  5. C#学习资料

    http://www.runoob.com/csharp/csharp-delegate.html

  6. ES6入门六:class的基本语法、继承、私有与静态属性、修饰器

    基本语法 继承 私有属性与方法.静态属性与方法 修饰器(Decorator) 一.基本语法 class Grammar{ constructor(name,age){ //定义对象自身的方法和属性 t ...

  7. selenium无头浏览器&规避操作

    一.无头浏览器概述: 无头浏览器主要目的是打开浏览器但用户看不到 简单用法如下: from selenium import webdriver from time import sleep from ...

  8. Linux内核的目录结构

  9. Windows Ping | Tracert 's Bat 脚本并行测试

    系统:windows 需求:测试多台PC输出三个网站并行ping.tracert结果,多台PC同时进行. 说明:以www.baidu.com.www.sina.com.cn.www.tencent.c ...

  10. win10家庭版设置移动热点出现“我们无法设置移动热点”

    寝室wifi卡到爆炸,  买了一个360随身WiFi,可是360随身WiFi烧坏了  ...然后我就一个星期没玩游戏了 今天本来想开电脑的wifi试一试,结果发现无法设置热点 纳闷了 百度一下,发现都 ...