2402: 陶陶的难题II

Time Limit: 40 Sec  Memory Limit: 128 MBSec  Special Judge
Submit: 68  Solved: 45
[Submit][Status]

Description

Input

第一行包含一个正整数N,表示树中结点的个数。
第二行包含N个正实数,第i个数表示xi (1<=xi<=10^5)。
第三行包含N个正实数,第i个数表示yi (1<=yi<=10^5)。
第四行包含N个正实数,第i个数表示pi (1<=pi<=10^5)。
第五行包含N个正实数,第i个数表示qi (1<=qi<=10^5)。
下面有N-1行,每行包含两个正整数a,b(1<=a,b<=N),表示树中的边。
第N+5行包含一个正整数M,表示询问的个数。
最后M行,每行包含正整数a,b(1<=a,b<=N),表示一次询问。

Output

共M行,每行一个实数,第i行的数表示第i次询问的答案。
只要你的输出和我们的输出相差不超过0.001即为正确。

Sample Input

5
3.0 1.0 2.0 5.0 4.0
5.0 2.0 4.0 3.0 1.0
1.0 3.0 2.0 4.0 5.0
3.0 4.0 2.0 1.0 4.0
1 2
1 3
2 4
2 5
4
2 3
4 5
2 4
3 5

Sample Output

2.5000
1.5000
1.5000
2.5000

HINT

100%的数据满足N,M≤ 30,000。

1<=Xi,Yi,Pi,Qi<=10^8

  注意题目中有这么一句话:“只要你的输出和我们的输出相差不超过0.001即为正确。”,这句话可以算作是二分答案的标志,由于1.4999...和1.5000...无论如何精确,四舍五入后都不同,所以这样的二分题只会用spj,反过来,也能证明这道题一定要用二分。

设原式x==p1
  y==v1
  p==p2
  q==v2

二分答案ans
  (v1+v2)/(p1+p2)>=ans
  (v1+v2)>=ans*p1+ans*p2
  (v1-ans*p1) + (v2-ans*p2)>=0
对于二分的ans我们只需要分别处理前半部分和后半部分的最大值即可。
  v1-ans*p1==c
  -p1*ans+v1==c
原式 -x*ans+y==c

  可看做对于区间内每一个(x,y),存在一条斜率k=-x,截距b=y的直线,套斜率优化的方法,预处理维护凸包链剖线段树维护即可。

  时间复杂度O(Qlog^3(n)),常数较小

  1. #include<iostream>
  2. #include<cstdio>
  3. #include<cstring>
  4. #include<algorithm>
  5. #include<vector>
  6. using namespace std;
  7. #define MAXN 31000
  8. #define MAXV MAXN
  9. #define MAXE MAXV*2
  10. #define MAXT MAXN*4
  11. #define lch (now<<1)
  12. #define rch (now<<1^1)
  13. #define smid ((sgt[now].l+sgt[now].r)>>1)
  14. #define maxval 1e8
  15. #define eps 1e-5
  16. #define inf 1e100
  17. typedef double real;
  18. int n;
  19. real v1[MAXN],v2[MAXN],v3[MAXN],v4[MAXN];
  20. int dfsq[MAXN];
  21. struct sgt_node
  22. {
  23. int l,r,lev;
  24. int tot0,tot1;
  25. }sgt[MAXT];
  26. struct line
  27. {
  28. real k,b;
  29. line(real k,real b):k(k),b(b){}
  30. line(){};
  31. real get_h(real x)
  32. {
  33. return k*x+b;
  34. }
  35. void print()
  36. {
  37. printf("Line: k=%.2lf b=%.2lf\n",k,b);
  38. }
  39. }sgc[][][MAXN];
  40. struct point
  41. {
  42. real x,y;
  43. point(real x,real y):x(x),y(y){};
  44. point(){}
  45. void print()
  46. {
  47. printf("Point: (%.2lf,%.2lf)\n",x,y);
  48. }
  49. }sgp[][][MAXN];
  50. bool cmp_point_x(const point &p1,const point &p2)
  51. {
  52. return p1.x<p2.x;
  53. }
  54. point crossover(line l1,line l2)
  55. {
  56. point res;
  57. res.x=(l1.b-l2.b)/(l2.k-l1.k);
  58. res.y=res.x*l1.k+l1.b;
  59. return res;
  60. }
  61. pair<real,real> sgt_getv(int now,real ps)
  62. {
  63. pair<real,real> res;
  64. int x;
  65. x=lower_bound(&sgp[][sgt[now].lev][sgt[now].l+],&sgp[][sgt[now].lev][sgt[now].l+sgt[now].tot0],point(ps,-inf),cmp_point_x)
  66. -sgp[][sgt[now].lev]-;
  67. res.first=sgc[][sgt[now].lev][x].get_h(ps);
  68. x=lower_bound(&sgp[][sgt[now].lev][sgt[now].l+],&sgp[][sgt[now].lev][sgt[now].l+sgt[now].tot1],point(ps,-inf),cmp_point_x)
  69. -sgp[][sgt[now].lev]-;
  70. res.second=sgc[][sgt[now].lev][x].get_h(ps);
  71. return res;
  72. }
  73. void Combine(line* res,point* pres,int& totr,line* h1,const int& tot1,line *h2,const int& tot2)
  74. {
  75. int t1,t2;
  76. line lnow;
  77. t1=t2=;
  78. while (t1!=tot1 || t2!=tot2)
  79. {
  80. if (t1<tot1 && t2<tot2)
  81. {
  82. if (h1[t1].k<h2[t2].k)
  83. {
  84. lnow=h1[t1++];
  85. }else
  86. {
  87. lnow=h2[t2++];
  88. }
  89. }else if (t1==tot1)
  90. {
  91. lnow=h2[t2++];
  92. }else if (t2==tot2)
  93. {
  94. lnow=h1[t1++];
  95. }
  96. if (totr<=)
  97. {
  98. res[totr]=lnow;
  99. if (totr)
  100. pres[totr]=crossover(res[totr-],res[totr]);
  101. totr++;
  102. }else
  103. {
  104. while (totr> && crossover(res[totr-],lnow).y>=pres[totr-].y)totr--;
  105. res[totr]=lnow;
  106. pres[totr]=crossover(res[totr-],res[totr]);
  107. totr++;
  108. }
  109. }
  110. }
  111. void Build_sgt(int now,int l,int r,int lev)
  112. {
  113. sgt[now].l=l,sgt[now].r=r;
  114. sgt[now].lev=lev;
  115. if (l==r)
  116. {
  117. sgc[][lev][l]=line(-v2[dfsq[l]],v1[dfsq[l]]);
  118. sgc[][lev][l]=line(-v4[dfsq[l]],v3[dfsq[l]]);
  119. sgt[now].tot0=sgt[now].tot1=;
  120. // printf("At position%d:\n",l);
  121. // printf("L1:");sgc[0][lev][l].print();
  122. //printf("L2:");sgc[1][lev][l].print();
  123. return ;
  124. }
  125. Build_sgt(lch,l,smid,lev+);
  126. Build_sgt(rch,smid+,r,lev+);
  127. Combine(&sgc[][lev][l],&sgp[][lev][l],sgt[now].tot0,&sgc[][lev+][l],sgt[lch].tot0,&sgc[][lev+][smid+],sgt[rch].tot0);
  128. Combine(&sgc[][lev][l],&sgp[][lev][l],sgt[now].tot1,&sgc[][lev+][l],sgt[lch].tot1,&sgc[][lev+][smid+],sgt[rch].tot1);
  129. /* printf("At position[%d,%d]:\n",l,r);
  130. for (int i=l;i<l+sgt[now].tot0;i++)
  131. {
  132. sgc[0][lev][i].print();
  133. if (i!=l)
  134. sgp[0][lev][i].print();
  135. }*/
  136. }
  137. void Query_sgt(int now,int l,int r,vector<int>& res)
  138. {
  139. if (sgt[now].l==l && sgt[now].r==r)
  140. {
  141. res.push_back(now);
  142. return ;
  143. }
  144. if (r<=smid)
  145. {
  146. Query_sgt(lch,l,r,res);
  147. }else if(smid<l)
  148. {
  149. Query_sgt(rch,l,r,res);
  150. }else
  151. {
  152. Query_sgt(lch,l,smid,res);
  153. Query_sgt(rch,smid+,r,res);
  154. }
  155. }
  156. struct Edge
  157. {
  158. int np,val;
  159. Edge *next;
  160. }E[MAXE],*V[MAXV];
  161. int tope=-;
  162. void addedge(int x,int y)
  163. {
  164. E[++tope].np=y;
  165. E[tope].next=V[x];
  166. V[x]=&E[tope];
  167. }
  168. int siz[MAXN],depth[MAXN];
  169. int pnt[MAXN];
  170. int top[MAXN],son[MAXN];
  171. void dfs1(int now)
  172. {
  173. Edge *ne;
  174. int mxsiz=;
  175. siz[now]=;
  176. for (ne=V[now];ne;ne=ne->next)
  177. {
  178. if (ne->np==pnt[now])continue;
  179. pnt[ne->np]=now;
  180. depth[ne->np]=depth[now]+;
  181. dfs1(ne->np);
  182. siz[now]+=siz[ne->np];
  183. if (siz[ne->np]>mxsiz)
  184. {
  185. mxsiz=siz[ne->np];
  186. son[now]=ne->np;
  187. }
  188. }
  189. }
  190. int pos[MAXN],dfstime;
  191. void dfs2(int now)
  192. {
  193. Edge *ne;
  194. pos[now]=++dfstime;
  195. dfsq[dfstime]=now;
  196. if (son[now])
  197. {
  198. top[son[now]]=top[now];
  199. dfs2(son[now]);
  200. }
  201. for (ne=V[now];ne;ne=ne->next)
  202. {
  203. if (ne->np==pnt[now] || ne->np==son[now])continue;
  204. top[ne->np]=ne->np;
  205. dfs2(ne->np);
  206. }
  207. }
  208. real search_m(int x,int y)
  209. {
  210. vector<pair<real,real> > vec1,vec2;
  211. while (x!=y)
  212. {
  213. if (depth[x]>=depth[y])
  214. {
  215. vec1.push_back(make_pair(v1[x],v2[x]));
  216. vec2.push_back(make_pair(v3[x],v4[x]));
  217. x=pnt[x];
  218. }else
  219. {
  220. vec1.push_back(make_pair(v1[y],v2[y]));
  221. vec2.push_back(make_pair(v3[y],v4[y]));
  222. y=pnt[y];
  223. }
  224. }
  225. vec1.push_back(make_pair(v1[x],v2[x]));
  226. vec2.push_back(make_pair(v3[x],v4[x]));
  227. real mxv=;
  228. for (int i=;i<vec1.size();i++)
  229. for (int j=;j<vec2.size();j++)
  230. mxv=max(mxv,(vec1[i].first+vec2[j].first)/(vec1[i].second+vec2[j].second));
  231. return mxv;
  232. }
  233.  
  234. int main()
  235. {
  236. freopen("input.txt","r",stdin);
  237. //设原式x==p1
  238. //y==v1
  239. //p==p2
  240. //q==v2
  241. //(v1+v2)/(p1+p2)>=ans
  242. //(v1+v2)>=ans*p1+ans*p2
  243. //(v1-ans*p1) + (v2-ans*p2)>=0
  244. //对于二分的ans我们只需要分别处理前半部分和后半部分的最大值即可。
  245. //v1-ans*p1==c
  246. //-p1*ans+v1==c
  247. //原式 -x*ans+y==c
  248. scanf("%d",&n);
  249. for (int i=;i<=n;i++)
  250. scanf("%lf",v2+i);//分母1
  251. for (int i=;i<=n;i++)
  252. scanf("%lf",v1+i);//分子1
  253. for (int i=;i<=n;i++)
  254. scanf("%lf",v4+i);//分母2
  255. for (int i=;i<=n;i++)
  256. scanf("%lf",v3+i);//分子2
  257. int x,y;
  258. for (int i=;i<n;i++)
  259. {
  260. scanf("%d%d",&x,&y);
  261. addedge(x,y);
  262. addedge(y,x);
  263. }
  264. dfs1();
  265. top[]=;
  266. dfs2();
  267. Build_sgt(,,n,);
  268. int q;
  269. real ans=;
  270. scanf("%d",&q);
  271. vector<int> vec;
  272. for (int i=;i<q;i++)
  273. {
  274. scanf("%d%d",&x,&y);
  275. vec.clear();
  276. while (true)
  277. {
  278. if (top[x]==top[y])
  279. {
  280. if (pos[x]>pos[y])swap(x,y);
  281. Query_sgt(,pos[x],pos[y],vec);
  282. break;
  283. }
  284. if (depth[top[x]]<depth[top[y]])swap(x,y);
  285. Query_sgt(,pos[top[x]],pos[x],vec);
  286. x=pnt[top[x]];
  287. }
  288. real l=,r=maxval;
  289. real mid;
  290. real mx1,mx2;
  291. while (r-l>eps)
  292. {
  293. mid=(l+r)/;
  294. mx1=mx2=-inf;
  295. pair<real,real> pr;
  296. for (int j=;j<vec.size();j++)
  297. {
  298. pr=sgt_getv(vec[j],mid);
  299. mx1=max(mx1,pr.first);
  300. mx2=max(mx2,pr.second);
  301. }
  302. if (mx1+mx2>=)
  303. l=mid;
  304. else
  305. r=mid;
  306. }
  307. printf("%.5lf\n",l+eps);
  308. }
  309. }

bzoj 2402: 陶陶的难题II 二分答案维护凸包的更多相关文章

  1. [BZOJ 2653] middle(可持久化线段树+二分答案)

    [BZOJ 2653] middle(可持久化线段树+二分答案) 题面 一个长度为n的序列a,设其排过序之后为b,其中位数定义为b[n/2],其中a,b从0开始标号,除法取下整. 给你一个长度为n的序 ...

  2. BZOJ 1570: [JSOI2008]Blue Mary的旅行( 二分答案 + 最大流 )

    二分答案, 然后对于答案m, 把地点分成m层, 对于边(u, v), 第x层的u -> 第x+1层的v 连边. 然后第x层的u -> 第x+1层的u连边(+oo), S->第一层的1 ...

  3. BZOJ 1196 [HNOI2006]公路修建问题(二分答案+并查集)

    [题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=1196 [题目大意] 对于每条可能维修的公路可选择修一级公路或者二级公路,价值不同 要求 ...

  4. BZOJ 1863: [Zjoi2006]trouble 皇帝的烦恼( 二分答案 )

    二分答案..然后从头到尾推一下, 看最后一个能不能取0个和第一个人相同的勋章 ------------------------------------------------------------- ...

  5. BZOJ:1816 [Cqoi2010]扑克牌 (贪心或二分答案)

    题面 \(solution:\) 这道题难就难在你能否读懂题目的意思,我们将它翻译一下: 现在我有n根竹子(每根竹子有\(c_i\)节,每节竹子高度为1),我可以通过消耗一点法力值使某一根竹子的某两节 ...

  6. BZOJ 4590 [Shoi2015]自动刷题机 ——二分答案

    二分答案水题. #include <cstdio> #include <cstring> #include <iostream> #include <algo ...

  7. BZOJ 4552 [Tjoi2016&Heoi2016]排序 ——线段树 二分答案

    听说是BC原题. 好题,二分答案变成01序列,就可以方便的用线段树维护了. 然后就是区间查询和覆盖了. #include <map> #include <cmath> #inc ...

  8. Bzoj 1926: [Sdoi2010]粟粟的书架(二分答案+乱搞+主席树)

    1926: [Sdoi2010]粟粟的书架 Time Limit: 30 Sec Memory Limit: 552 MB Description 幸福幼儿园 B29 班的粟粟是一个聪明机灵.乖巧可爱 ...

  9. poj2018 Best Cow Fences[二分答案or凸包优化]

    题目. 首先暴力很好搞,但是优化的话就不会了.放弃QWQ. 做法1:二分答案 然后发现平均值是$ave=\frac{sum}{len}$,这种形式似乎可以二分答案?把$len$移到左边. 于是二分$a ...

随机推荐

  1. Amazon EC2上搭建VPN服务器

    Amazon EC2 提供了一年免费试用,Micro Instance,配置是 1G 内存,共享 CPU,和每月 15G 的流量.搭一个 VPN 服务器绰绰有余了.操作系统我选的是 Amazon Li ...

  2. 鸭子类型duck typing(动态)

    在程序设计中,鸭子类型(duck typing)是动态类型的一种风格.在这种风格中,一个对象有效的语义,不是由继承自特定的类或实现特定的接口,而是由当前方法和属性的集合决定.这个概念的名字来源于由Ja ...

  3. C# select的联动效果

    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"><html><head&g ...

  4. 20160410javaweb之JDBC---DBUtils框架

    DBUtils 1.DbUtils 工具类 2.QueryRunner -- 两行代码搞定增删改查 (1)QueryRunner() --需要控制事务时,使用这组方法 int update(Conne ...

  5. jdbc-connect-oracle12c-pdb/cdb(jdbc连接oracle12c的pdb和cdb)

      1       本文简介: 通过特意引发问题,聚焦问题,解决问题,并循序渐进 最后总结jdbc连接oracle12c中cdb和pdb的条件. 软件环境:Redhat7.1+orcacle12c 2 ...

  6. switch case实现两个数的算术运算

    方法一: package com.liaojianya.chapter1; import java.util.Scanner; public class SwitchDemo1 { public st ...

  7. Codevs 1066 引水入城 2010年NOIP全国联赛提高组

    1066 引水入城 2010年NOIP全国联赛提高组 时间限制: 1 s 空间限制: 128000 KB 题目等级 : 钻石 Diamond 传送门 题目描述 Description 在一个遥远的国度 ...

  8. QListWidget 删除选中项目

    void MainWindow::on_action_Del_triggered() { QList<QListWidgetItem*> selectedItems = ui->li ...

  9. 计数排序之python 实现源码

    old = [2, 5, 3, 0, 2, 3, 0, 3] new = [0, 0, 0, 0, 0, 0] for i in range(len(old)): new[old[i]] = new[ ...

  10. 数据结构学习——shell排序的C语言实现

    shell排序: 这个排序的命名是来自发明者的名字,和排序的方法没有字面上的联系.所以不要因为名字而感觉很难.在K&R的C程序设计语言中书中只用了几行代码很简洁的实现了这个排序算法.那就来看看 ...