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)),常数较小

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
using namespace std;
#define MAXN 31000
#define MAXV MAXN
#define MAXE MAXV*2
#define MAXT MAXN*4
#define lch (now<<1)
#define rch (now<<1^1)
#define smid ((sgt[now].l+sgt[now].r)>>1)
#define maxval 1e8
#define eps 1e-5
#define inf 1e100
typedef double real;
int n;
real v1[MAXN],v2[MAXN],v3[MAXN],v4[MAXN];
int dfsq[MAXN];
struct sgt_node
{
int l,r,lev;
int tot0,tot1;
}sgt[MAXT];
struct line
{
real k,b;
line(real k,real b):k(k),b(b){}
line(){};
real get_h(real x)
{
return k*x+b;
}
void print()
{
printf("Line: k=%.2lf b=%.2lf\n",k,b);
}
}sgc[][][MAXN];
struct point
{
real x,y;
point(real x,real y):x(x),y(y){};
point(){}
void print()
{
printf("Point: (%.2lf,%.2lf)\n",x,y);
}
}sgp[][][MAXN];
bool cmp_point_x(const point &p1,const point &p2)
{
return p1.x<p2.x;
}
point crossover(line l1,line l2)
{
point res;
res.x=(l1.b-l2.b)/(l2.k-l1.k);
res.y=res.x*l1.k+l1.b;
return res;
}
pair<real,real> sgt_getv(int now,real ps)
{
pair<real,real> res;
int x;
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)
-sgp[][sgt[now].lev]-;
res.first=sgc[][sgt[now].lev][x].get_h(ps);
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)
-sgp[][sgt[now].lev]-;
res.second=sgc[][sgt[now].lev][x].get_h(ps);
return res;
}
void Combine(line* res,point* pres,int& totr,line* h1,const int& tot1,line *h2,const int& tot2)
{
int t1,t2;
line lnow;
t1=t2=;
while (t1!=tot1 || t2!=tot2)
{
if (t1<tot1 && t2<tot2)
{
if (h1[t1].k<h2[t2].k)
{
lnow=h1[t1++];
}else
{
lnow=h2[t2++];
}
}else if (t1==tot1)
{
lnow=h2[t2++];
}else if (t2==tot2)
{
lnow=h1[t1++];
}
if (totr<=)
{
res[totr]=lnow;
if (totr)
pres[totr]=crossover(res[totr-],res[totr]);
totr++;
}else
{
while (totr> && crossover(res[totr-],lnow).y>=pres[totr-].y)totr--;
res[totr]=lnow;
pres[totr]=crossover(res[totr-],res[totr]);
totr++;
}
}
}
void Build_sgt(int now,int l,int r,int lev)
{
sgt[now].l=l,sgt[now].r=r;
sgt[now].lev=lev;
if (l==r)
{
sgc[][lev][l]=line(-v2[dfsq[l]],v1[dfsq[l]]);
sgc[][lev][l]=line(-v4[dfsq[l]],v3[dfsq[l]]);
sgt[now].tot0=sgt[now].tot1=;
// printf("At position%d:\n",l);
// printf("L1:");sgc[0][lev][l].print();
//printf("L2:");sgc[1][lev][l].print();
return ;
}
Build_sgt(lch,l,smid,lev+);
Build_sgt(rch,smid+,r,lev+);
Combine(&sgc[][lev][l],&sgp[][lev][l],sgt[now].tot0,&sgc[][lev+][l],sgt[lch].tot0,&sgc[][lev+][smid+],sgt[rch].tot0);
Combine(&sgc[][lev][l],&sgp[][lev][l],sgt[now].tot1,&sgc[][lev+][l],sgt[lch].tot1,&sgc[][lev+][smid+],sgt[rch].tot1);
/* printf("At position[%d,%d]:\n",l,r);
for (int i=l;i<l+sgt[now].tot0;i++)
{
sgc[0][lev][i].print();
if (i!=l)
sgp[0][lev][i].print();
}*/
}
void Query_sgt(int now,int l,int r,vector<int>& res)
{
if (sgt[now].l==l && sgt[now].r==r)
{
res.push_back(now);
return ;
}
if (r<=smid)
{
Query_sgt(lch,l,r,res);
}else if(smid<l)
{
Query_sgt(rch,l,r,res);
}else
{
Query_sgt(lch,l,smid,res);
Query_sgt(rch,smid+,r,res);
}
}
struct Edge
{
int np,val;
Edge *next;
}E[MAXE],*V[MAXV];
int tope=-;
void addedge(int x,int y)
{
E[++tope].np=y;
E[tope].next=V[x];
V[x]=&E[tope];
}
int siz[MAXN],depth[MAXN];
int pnt[MAXN];
int top[MAXN],son[MAXN];
void dfs1(int now)
{
Edge *ne;
int mxsiz=;
siz[now]=;
for (ne=V[now];ne;ne=ne->next)
{
if (ne->np==pnt[now])continue;
pnt[ne->np]=now;
depth[ne->np]=depth[now]+;
dfs1(ne->np);
siz[now]+=siz[ne->np];
if (siz[ne->np]>mxsiz)
{
mxsiz=siz[ne->np];
son[now]=ne->np;
}
}
}
int pos[MAXN],dfstime;
void dfs2(int now)
{
Edge *ne;
pos[now]=++dfstime;
dfsq[dfstime]=now;
if (son[now])
{
top[son[now]]=top[now];
dfs2(son[now]);
}
for (ne=V[now];ne;ne=ne->next)
{
if (ne->np==pnt[now] || ne->np==son[now])continue;
top[ne->np]=ne->np;
dfs2(ne->np);
}
}
real search_m(int x,int y)
{
vector<pair<real,real> > vec1,vec2;
while (x!=y)
{
if (depth[x]>=depth[y])
{
vec1.push_back(make_pair(v1[x],v2[x]));
vec2.push_back(make_pair(v3[x],v4[x]));
x=pnt[x];
}else
{
vec1.push_back(make_pair(v1[y],v2[y]));
vec2.push_back(make_pair(v3[y],v4[y]));
y=pnt[y];
}
}
vec1.push_back(make_pair(v1[x],v2[x]));
vec2.push_back(make_pair(v3[x],v4[x]));
real mxv=;
for (int i=;i<vec1.size();i++)
for (int j=;j<vec2.size();j++)
mxv=max(mxv,(vec1[i].first+vec2[j].first)/(vec1[i].second+vec2[j].second));
return mxv;
} int main()
{
freopen("input.txt","r",stdin);
//设原式x==p1
//y==v1
//p==p2
//q==v2
//(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
scanf("%d",&n);
for (int i=;i<=n;i++)
scanf("%lf",v2+i);//分母1
for (int i=;i<=n;i++)
scanf("%lf",v1+i);//分子1
for (int i=;i<=n;i++)
scanf("%lf",v4+i);//分母2
for (int i=;i<=n;i++)
scanf("%lf",v3+i);//分子2
int x,y;
for (int i=;i<n;i++)
{
scanf("%d%d",&x,&y);
addedge(x,y);
addedge(y,x);
}
dfs1();
top[]=;
dfs2();
Build_sgt(,,n,);
int q;
real ans=;
scanf("%d",&q);
vector<int> vec;
for (int i=;i<q;i++)
{
scanf("%d%d",&x,&y);
vec.clear();
while (true)
{
if (top[x]==top[y])
{
if (pos[x]>pos[y])swap(x,y);
Query_sgt(,pos[x],pos[y],vec);
break;
}
if (depth[top[x]]<depth[top[y]])swap(x,y);
Query_sgt(,pos[top[x]],pos[x],vec);
x=pnt[top[x]];
}
real l=,r=maxval;
real mid;
real mx1,mx2;
while (r-l>eps)
{
mid=(l+r)/;
mx1=mx2=-inf;
pair<real,real> pr;
for (int j=;j<vec.size();j++)
{
pr=sgt_getv(vec[j],mid);
mx1=max(mx1,pr.first);
mx2=max(mx2,pr.second);
}
if (mx1+mx2>=)
l=mid;
else
r=mid;
}
printf("%.5lf\n",l+eps);
}
}

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. android自定义View之NotePad出鞘记

    现在我们的手机上基本都会有一个记事本,用起来倒也还算方便,记事本这种东东,如果我想要自己实现,该怎么做呢?今天我们就通过自定义View的方式来自定义一个记事本.OK,废话不多说,先来看看效果图. 整个 ...

  2. apktool重打包签名后安装出现“Failure [INSTALL_FAILED_ALREADY_EXISTS]”

    一般修改.签名环节不出错的话,可以考虑看是不是包名重复的问题,如果系统中存在相同包名的应用,安装时会报这个错误 就算apk名字变了,但和原来的包名仍是一样的,所以先卸载掉系统里同包名的应用,再尝试安装 ...

  3. 练习题之ThreadLocal

    public class ThreadLocalMain { private static ThreadLocal<Integer> value = new ThreadLocal< ...

  4. struts1与struts2的区别

    Struts2其实并不是一个陌生的Web框架,Struts2是以Webwork的设计思想为核心,吸收了Struts1的优点,因此,可以认为Struts2是Struts1和Webwork结合的产物. 简 ...

  5. C#相关时间DateTime格式化

    C#代码中时间转换为2016-01-24 12:12:12需要如下操作: DateTime.Parse(sj).ToString("yyyy-MM-dd HH:m:ss") 但是O ...

  6. SharePoint 页面Pages和SitePages目录创建不成功解决

    最近项目中要用到Pages及SitePages目录中的一个 可是目录时,不是发现没有Pages就是没SitePages: 分析后才得知Pages目录需要开户SharePoint Server Publ ...

  7. 1_使用Java文件的并发写

    为了实现,并发写操作,首先实验一下在本地情况下, 将一个文件切分成若干个 文件块 然后将文件块 通过多线程的并发的方式写入到指定目录下的文件中. 下面是简单的试着实现代码,暂时 先进行记录一下: im ...

  8. iOS 中二维码扫描(zxingObjc和原生)

    对于网上的第三方 ZXingObjC,自我感觉是对原生的AVFoundation中关于二维码部分的一个封装,大致看看ZXingObjC的内部实现其事和原生的实现相似的,里面都用到了AVFoundati ...

  9. 类型与通用语言运行时:System.Object

    CLR 要求每个类型最终都要继承自 System.Object 类型 //隐式继承 Object class Employee { ... } //显示继承继承 Object class Employ ...

  10. js判断主流浏览器类型和版本号

    如今的互联网中,浏览器可以说是太多太多了,但是大部分都是换壳不换心,基本上主流的浏览器还是火狐,谷歌,IE,safrai这几种比较常见,所以在我们的开发中,有时候需要遇到判断用户正在使用什么浏览器以及 ...