您的位置:首页 > 运维架构

【树链剖分+维护凸线】Saber

2012-03-10 15:28 190 查看
秋哥是saber控,每次saber都很难,但是还有两种颜色的saber没出。

有一棵 n 个点的树,每个点有四个权值 x,y,p,q,给出 m 个询问(a,b),假设 i,j 为 a 到

b 的路径上的可以重合的两个点,求(yi+qj)/(xi+pj)的最大值。

二分答案,就化出了(x,y)与(p,q)分开的式子,分别对此两式求最大值判断,用斜率的经典分析来看(x,y)

若有一k比i优,则

yk-ans*xk>=yi-ans*xi

yk-yi>=ans*(xk-xi)

(yk-yi)/(xk-xi)>=ans

因此维护一个斜率单减的队列,每次二分<ans的位置即可找到当前区间最大值,可是这是一颗树,很自然想到树链剖分,但是整个区间二分肯定包含非此路径节点,于是用线段树维护恰好包含的区间,每个节点还得额外储存队列,这里面有多少log我也不想搞清了,反正最外面那层二分不改成迭代对于秋哥的数据会卡着时间超3个点。

#include <cstdio>
#include <cstring>
#include <cstdlib>
const int oo=1073741819,maxn=100000;
const double eps=1e-3;
int t[2],rt[maxn],f[maxn],d[maxn],next[maxn],sora[maxn],tail[maxn],o[maxn],s1,ss,n,m,p[maxn],up[maxn],m1;
double sum[2],ans[2];
struct lisan{int o,d,i;}b[65536];
struct room{double x,y;}u[2][300000];
struct inf{double x,y,p,q;}a[maxn];
inline double max(double x,double y) {return (x>y) ? x : y;}
struct seg
{
  int h,r,k;
  double check(room a,room b) {return (b.y-a.y)/(b.x-a.x);}
  inline void ori(int l1,int r1,int l2,int r2)
  {
    room ne;
    h=r=++t[k];
    for (r--;(((l1<=r1)&&(r1))||((l2<=r2)&&(r2)));) {
      if (((u[k][l1].x<u[k][l2].x)&&(l1<=r1))||(l2>r2)) ne=u[k][l1],l1++;else ne=u[k][l2],l2++;
      for (;(h<r)&&(check(u[k][r],ne)>check(u[k][r-1],u[k][r]));r--) ;
      u[k][++r]=ne;
    }
    if (h>r) r=0,h=1;else t[k]=r;
  }
  inline double search(double x)
  {
    int ll,rr,mid;
    for (ll=h+1,rr=r;ll<=rr;) {
      mid=(ll+rr)>>1;
      if (check(u[k][mid-1],u[k][mid])>x) ll=mid+1;else rr=mid-1;
    }
    if (ll<=r) return max(u[k][ll-1].y-x*u[k][ll-1].x,u[k][ll].y-x*u[k][ll].x);
    else return u[k][ll-1].y-x*u[k][ll-1].x;
  }
}c[2][65536];
inline void dfs(int x,int y,int dep)
{
  int i,ne;
  rt[x]=y,f[x]=1,d[x]=dep;
  int max=-oo,maxi=0;
  for (i=x;next[i]!=0;) {
    i=next[i],ne=sora[i];
    if (ne!=y) {
      dfs(ne,x,dep+1),f[x]+=f[ne];
      if (f[ne]>max) max=f[ne],maxi=ne;
    }
  }
  if (maxi!=0) o[x]=o[maxi];else o[x]=++s1;
}
inline int cmp(const void *i,const void *j)
{
  lisan p=*(lisan *)i,q=*(lisan *)j;
  if (p.o!=q.o) return p.o-q.o;
  return p.d-q.d;
}
void ori()
{
  int i;
  for (i=1;i<=n;i++) b[i].i=i,b[i].o=o[i],b[i].d=d[i];
  qsort(b+1,n,sizeof(b[1]),cmp);
  for (i=1;i<=n;i++) {
    p[b[i].i]=i;
    if (b[i].o!=b[i-1].o) up[b[i].o]=b[i].i;
  }
  for (i=1;i<=n;i++) {
    c[0][i+m1].h=c[0][i+m1].r=++t[0],c[1][i+m1].h=c[1][i+m1].r=++t[1];
    c[0][i+m1].k=0,c[1][i+m1].k=1;
    u[0][t[0]].x=a[b[i].i].x,u[0][t[0]].y=a[b[i].i].y,
    u[1][t[1]].x=a[b[i].i].p,u[1][t[1]].y=a[b[i].i].q;
  }
  for (i=m1-1;i>=1;i--) {
    c[0][i].k=0,c[1][i].k=1;
    c[0][i].ori(c[0][i<<1].h,c[0][i<<1].r,c[0][(i<<1)+1].h,c[0][(i<<1)+1].r);
    c[1][i].ori(c[1][i<<1].h,c[1][i<<1].r,c[1][(i<<1)+1].h,c[1][(i<<1)+1].r);
  }
}
void origin() 
{
  int i;
  for (m1=1;m1<=n+2;m1<<=1) ;t[0]=t[1]=m1+m1;
  for (i=1;i<=n;i++) tail[i]=i;ss=n;
}
inline double ask(int k,int l,int r,double x)
{
  double ans;
  l+=m1-1,r+=m1+1,ans=-oo;
  for (;!(1==(l^r));l>>=1,r>>=1) {
    if (0==(l&1)) ans=max(ans,c[k][l+1].search(x));
    if (1==(r&1)) ans=max(ans,c[k][r-1].search(x));
  }
  return ans;
}
inline void updata(int &l,double x)
{
    sum[0]=ask(0,p[up[o[l]]],p[l],x);sum[1]=ask(1,p[up[o[l]]],p[l],x);
    ans[0]=max(ans[0],sum[0]);ans[1]=max(ans[1],sum[1]);
    l=rt[up[o[l]]];
}
inline int find(double x,int l,int r)
{
  int e;
  ans[0]=ans[1]=-oo;
  for (;;) {
    if (o[l]==o[r]) {
      if (d[l]<d[r]) e=l,l=r,r=e;
      sum[0]=ask(0,p[r],p[l],x);sum[1]=ask(1,p[r],p[l],x);
      ans[0]=max(ans[0],sum[0]);ans[1]=max(ans[1],sum[1]);
      break;
    }
    else 
      if (d[up[o[l]]]>=d[up[o[r]]]) updata(l,x);else updata(r,x);
  }
  if (ans[0]+ans[1]>0) return 1;else return 0;
}
inline void link(int x,int y)
{
  ss++,next[tail[x]]=ss,tail[x]=ss,sora[ss]=y;
  ss++,next[tail[y]]=ss,tail[y]=ss,sora[ss]=x;
}
inline int equ(double x,double y) {return ((y-x)>-eps)&&((y-x)<eps);}
void init()
{
  int i,x,y;
  double l,r,mid;
  scanf("%d\n",&n);
  origin();
  for (i=1;i<=n;i++) scanf("%llf",&a[i].x);
  for (i=1;i<=n;i++) scanf("%llf",&a[i].y);  
  for (i=1;i<=n;i++) scanf("%llf",&a[i].p);  
  for (i=1;i<=n;i++) scanf("%llf",&a[i].q);  
  for (i=1;i<=n-1;i++) scanf("%d%d",&x,&y),link(x,y);
  dfs(1,0,0);
  ori();
  scanf("%d\n",&m);
  for (i=1;i<=m;i++) {
    scanf("%d%d\n",&x,&y);
    for (l=0,r=100000;!equ(l,r);) {
      mid=(l+r)/2;
      if (find(mid,x,y)) l=mid;else r=mid;
    }
    printf("%.4llf\n",l);
  }
}
int main()
{
  freopen("saber.in","r",stdin);
  freopen("saber.out","w",stdout);
    init();
  return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: