毒瘤,毒瘤,毒瘤……

\(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-2325】道馆之战 树链剖分 + 线段树

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

  2. BZOJ3862Little Devil I——树链剖分+线段树

    题目大意: 给一棵树,每条边可能是黑色或白色(起始都是白色),有三种操作: 1.将u到v路径上所有边颜色翻转(黑->白,白->黑) 2.将只有一个点在u到v路径上的边颜色翻转 3.查询u到 ...

  3. CodeForces - 160D Edges in MST(思维+tarjan/树链剖分+线段树)

    题目链接:点击查看 题目大意:给出一张 n 个点 m 条边组成的带权无向图,现在对于每条边来说,确定一下其分类: 一定是最小生成树上的边 可能是最小生成树上的边 一定不是最小生成树的边 题目分析:两种 ...

  4. CodeForces - 609E Minimum spanning tree for each edge(最小生成树+树链剖分+线段树/树上倍增)

    题目链接:点击查看 题目大意:给出一张 n 个点和 m 条边组成的无向图,现在询问包含每一条边的最小生成树 题目分析:考虑求解次小生成树的思路: 求出最小生成树 ans 枚举每一条非树边 ( u , ...

  5. P2486 [SDOI2011]染色(树链剖分+线段树)

    题干描述 输入描述 输出格式 对于每个询问操作,输出一行答案. 输入输出样例 输入 #1 复制 6 5 2 2 1 2 1 1 1 2 1 3 2 4 2 5 2 6 Q 3 5 C 2 1 1 Q ...

  6. BZOJ4127Abs——树链剖分+线段树

    题目描述 给定一棵树,设计数据结构支持以下操作 1 u v d 表示将路径 (u,v) 加d 2 u v 表示询问路径 (u,v) 上点权绝对值的和 输入 第一行两个整数n和m,表示结点个数和操作数 ...

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

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

  8. HDU 2460 Network(双连通+树链剖分+线段树)

    HDU 2460 Network 题目链接 题意:给定一个无向图,问每次增加一条边,问个图中还剩多少桥 思路:先双连通缩点,然后形成一棵树,每次增加一条边,相当于询问这两点路径上有多少条边,这个用树链 ...

  9. BZOJ2325[ZJOI2011]道馆之战——树链剖分+线段树

    题目描述 口袋妖怪(又名神奇宝贝或宠物小精灵)红/蓝/绿宝石中的水系道馆需要经过三个冰地才能到达馆主的面前,冰地中 的每一个冰块都只能经过一次.当一个冰地上的所有冰块都被经过之后,到下一个冰地的楼梯才 ...

  10. YbtOJ-染色计划【树链剖分,线段树,tarjan】

    正题 题目大意 给出nnn个点的一棵树,每个点有个颜色aia_iai​,你每次可以选择一个颜色全部变成另一个颜色. 求最少多少次操作可以把一种颜色变成一个完整的连通块. 1≤k≤n≤2×1051\le ...

最新文章

  1. Windows10安装TensorFlow GPU版本
  2. 抖音快手小视频推荐算法之--协同过滤算法剖析
  3. 被文献坑是一种什么样的体验?
  4. springboot日志配输出路径配置_SpringBoot日志配置详解
  5. EXTI外部中断触发:神舟IV
  6. python的with用法
  7. dubbo 支持服务降级吗_Dubbo服务降级设置
  8. 关于虚拟机,影子系统和游戏机器码的问题
  9. 基于JavaWeb的在线题库管理系统的设计与开发
  10. 极力推荐收藏的几个高清免费图片素材网站
  11. OOAD作业计算圆柱体和三棱柱体的体积
  12. arcgis做dijkstra_GIS最短路径分析中Dijkstra算法的优化
  13. 浅谈如何做好督查督办工作?
  14. 计算机开机进不去桌面,电脑开机直接跳过启动界面进去电脑桌面,想进bios进不去怎么办...
  15. php生成云图,教程:用Python生成词云图
  16. 「雕爷学编程」Arduino动手做(25)——MQ2气敏检测模块
  17. unity中多屏显示
  18. 百度地图根据经纬度判断点是否在行政区内
  19. [概率论]图像里的“白噪声”——电视机搜不到台时雪花斑点的形成原因 (不信谣,不传谣,与宇宙微波背景辐射没有任何关系)
  20. 好好爱自己,胜过千言万语

热门文章

  1. 帝国CMS后台前台上传大小和类型限制的解决方法!
  2. PYQT5 多选下拉列表框
  3. javascript中的事件处理
  4. 在tensorflow中的网格图问题--np.mgrid()
  5. 25匹马,找出最快的3匹,但是只有5个赛道,每次比赛只能得到5匹马的速度排序,那么最少需要多少次比赛
  6. 任务切换——《x86汇编语言:从实模式到保护模式》读书笔记38
  7. 【存储技术大杂烩】谈谈FC-SAN、IP-SAN、DAS、NAS几种存储技术
  8. maven生命周期lifecycle和plugins介绍
  9. 服务器 Font family [‘sans-serif‘] not found.Falling back to DejaVu Sans.解决办法
  10. Hi3516A开发--/etc/passwd