WC 2010 rebuild 重建计划

来源:互联网 发布:matlab等差数组 编辑:程序博客网 时间:2024/05/21 17:41

题目描述就不说了。要题目的请往百度NOI吧。

经典的树的分治,首先,对于答案是分数形式的基本上要使用二分答案,这不是胡扯,详情请见胡伯涛的论文。

那么对于这个题,由于不好估计边分治复杂度(其实边分治是可以过的,好像比点分治要快),对于答案,化成如下形式sigma{e}-ans*s=0,对于一个可行的ans设为val,必然满足sigma{e}-val*s>=0,所以二分。

点分治时,将每个节点到根的路径的权值计算出来,同时记录走过了多少条边。然后按照在每个子树中按照路径走过的边的数目排序,二分答案后验证,合并子树时,第一颗子树在一个数组list中按序保存走过s条边的路径权值最大值,以后的子树中枚举每条路径,利用单调性每次从list中加入一个值用单调队列维护路径的合法性和最优性,在做完一颗子树后这个子树保存的路径与list数组保存的信息合并,作为下一次list使用。

复杂度分析:点分治O(nlogn),每个节点被访问logn+1次,排序O(nlogn)为上限,二分答案验证为O(nlogans),一共做logn次,所以为O(nlognlogans)

Code:(注:不要作为对拍程序,貌似实现有bug)

#include<cstdio>#include<cstdlib>#include<cmath>#include<cstring>struct element{  int key;  double val;} que[100005],lis[2][100005];const double oo=10000000;const element ori={0,0};int vis[100005],sta[100005],next[200005],link[200005],head[100005],sum[100005],f[100005],l[100005],r[100005],dis[100005],a[100005],b[100005],count[100005],w[200005],pre[200005],tot[2],hea=0,tai=0;bool flag[100005];int time=0,top=0,tail=0,now=0,e=1,up=0,dn=0,n=0;double ans=0,limitup=0,limitdn=0,mid=0;inline void add(int u,int v,int tmpw){  next[++e]=head[u];  head[u]=e;  link[e]=v;  w[e]=tmpw;  pre[next[e]]=e;  next[++e]=head[v];  head[v]=e;  link[e]=u;  w[e]=tmpw;  pre[next[e]]=e;}inline void update(double &a,double b){  if (a<b) a=b;}inline int cal(int s){  ++time;  f[s]=0;  top=0;  vis[s]=time;  sta[tail=1]=s;  int ne=0,y=0,x=0,i=0;  while (top<tail)    {      x=sta[++top];      for (ne=head[x],y=link[ne];ne;ne=next[ne],y=link[ne])if (vis[y]!=time)  {    vis[y]=time;    sta[++tail]=y;    f[y]=x;  }      sum[x]=0;      flag[x]=1;    }  if (tail==1) return s;  for (i=tail,x=sta[i];i>=1;i--,x=sta[i])    {      sum[x]++;      sum[f[x]]+=sum[x];      if (sum[x]<=tail/2) flag[x]=0;      if (sum[x]>tail/2) flag[f[x]]=0;      if (flag[x]) return x;    }}void print(int s){  for (;s;s=f[s])    printf("%d ",s);  printf("\n");}void dfs(int s){  vis[s]=time;  int ne=0,x=0;  l[s]=r[s]=++now;  a[now]=dis[s];  b[now]=count[s];  for (ne=head[s],x=link[ne];ne;ne=next[ne],x=link[ne])    if (vis[x]!=time)      {f[x]=s;dis[x]=dis[s]+w[ne];count[x]=count[s]+1;if (dn<=count[x] && count[x]<=up) update(ans,(double)(dis[x])/count[x]);dfs(x);r[s]=r[x];      }}inline void swap(int &a,int &b){  int tmp=a;  a=b;  b=tmp;}inline void qs(int h,int g){  int l=h,k=g,mid=b[(l+k)/2];  while (l<=k)    {      while (b[l]<mid) l++;      while (b[k]>mid) k--;      if (l<=k){  swap(b[l],b[k]);  swap(a[l],a[k]);  l++;  k--;}    }  if (l<g) qs(l,g);  if (h<k) qs(h,k);}inline bool com(int st){  return (dn<=st && st<=up);}bool check(double mid,int s){  int ne=head[s],x=link[ne],i=0,j=0,now=0,oth=1;  double tmpw=0;  tot[0]=tot[1]=hea=tai=0;  for (i=l[x];i<=r[x];i++)    {      if (b[i]==b[i-1]) update(lis[now][tot[now]].val,a[i]-b[i]*mid);      else{  lis[now][++tot[now]].val=a[i]-b[i]*mid;  lis[now][tot[now]].key=b[i];}    }  for (ne=next[ne],x=link[ne];ne;ne=next[ne],x=link[ne])    {      hea=tai=0;      j=tot[now];      for (i=l[x];i<=r[x];i++){  tmpw=a[i]-b[i]*mid;  for (;!com(que[hea].key+b[i]) && hea<=tai;hea++);  for (;lis[now][j].key+b[i]>up && j>0;j--);  for (;com(lis[now][j].key+b[i]) && j>0;j--)    {      for (;lis[now][j].val>que[tai].val && hea<=tai;tai--);      que[++tai]=lis[now][j];    }  if (hea<=tai && que[hea].val+tmpw>-(1e-5) && com(que[hea].key+b[i])) return 1;}      oth=now;      now=1-now;      tot[now]=0;      i=l[x];j=1;      lis[oth][tot[oth]+1].key=n+1;      while (i<=r[x] || j<=tot[oth]){  for (;i<=r[x] && lis[now][tot[now]].key==b[i];i++)    update(lis[now][tot[now]].val,a[i]-b[i]*mid);  for (;j<=tot[oth] && lis[now][tot[now]].key==lis[oth][j].key;j++)    update(lis[now][tot[now]].val,lis[oth][j].val);  if (i<=r[x])    if (b[i]<=lis[oth][j].key)      lis[now][++tot[now]].key=b[i],lis[now][tot[now]].val=a[i]-b[i]*mid,i++;    else      lis[now][++tot[now]]=lis[oth][j],j++;  else    if (j<=tot[oth])      lis[now][++tot[now]]=lis[oth][j],j++;}    }  return 0;}void getans(int s){  if (tail<dn) return;  ++time;  now=0;  dis[s]=0;count[s]=0;  f[s]=0;  limitdn=0;  dfs(s);  limitup=1e6;  int ne=0,x=0,me=0;  for (ne=head[s],x=link[ne];ne;ne=next[ne],x=link[ne])    qs(l[x],r[x]);  while (limitdn+1e-5<limitup)    {      mid=(limitup+limitdn)/2;      if (check(mid,s))limitdn=mid;      elselimitup=mid;    }  update(ans,limitdn);  for (ne=head[s],x=link[ne],me=ne^1;ne;ne=next[ne],x=link[ne],me=ne^1)    {      if (head[x]==me){  head[x]=next[me];  pre[next[me]]=0;}      else{  next[pre[me]]=next[me];  pre[next[me]]=pre[me];}      pre[me]=0;next[me]=0;link[me]=0;w[me]=0;      getans(cal(x));    }}int main(){  freopen("rebuild.in","r",stdin);  freopen("rebuild.out","w",stdout);  scanf("%d%d%d",&n,&dn,&up);  int i=0,u=0,v=0,tmpw=0;  for (i=1;i<n;i++)    {      scanf("%d%d%d",&u,&v,&tmpw);      add(u,v,tmpw);    }  ans=-oo;  getans(cal(1));  printf("%.3f",ans);  return 0;}