[WC2010]重建计划

题目大意:
  给定一棵带权树,试找出长度在L和U之间的路径,使得权值和与路径长度比最大,求出这个权值。

思路:
  “权值和与路径长度比最大”显然是一个经典的分数规划问题,考虑使用二分答案,
  设每次二分出来的答案是m,将树上的每一条边减去m,这样问题就转化成了寻找一条边权和大于等于0的路径。
  每次二分检验时,可以使用点分,找出经过当前重心的满足条件的路径。
  我们可以先将子树内各个结点到重心的路径的边权和球出来,如果每次枚举每个点对,那么复杂度是O(n^2)的,显然会TLE。
  经过观察,我们可以发现,每条路径仅与其边权和及路径长度有关,因此我们可以考虑对于每个相同的路径长度,记录其中最大的边权和,
  使用两个数组max和tmax,max记录的是当前重心的前几个子树最大边权和,于每个tmax[i],它对应的l,u区间是可以单向滑动的,因此我们可以使用单调队列在线性时间内维护一棵子树。
  因为树是静态的,因此每次找到的重心都不会变,如果每次二分以后都要找一边重心,显然是很不划算的,因此我们可以先预处理出每一次找到的中心,另外,对于大小小于l的子树,肯定不存在合法的路径,因此可以直接忽略。
  这道题似乎特别卡常,而且容易栈溢出(即使没有死递归)。最后还是手动开大栈才过的。

  1 #include<deque>
  2 #include<cstdio>
  3 #include<cctype>
  4 #include<vector>
  5 #include<cstring>
  6 #include<algorithm>
  7 inline int getint() {
  8     char ch;
  9     while(!isdigit(ch=getchar()));
 10     int x=ch^'0';
 11     while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0');
 12     return x;
 13 }
 14 const int inf=0x7fffffff,_inf=-0x80000000;
 15 const double eps=1e-4;
 16 const int V=100001;
 17 struct Edge {
 18     int to,w;
 19 };
 20 std::vector<Edge> e[V];
 21 inline void add_edge(const int u,const int v,const int w) {
 22     e[u].push_back((Edge){v,w});
 23 }
 24 bool is_centroid[V]={0};
 25 int centroid[V]={0},size[V];
 26 int now_centroid,tree_size,min_size;
 27 void get_size(const int x,const int par) {
 28     size[x]=1;
 29     int max=0;
 30     for(unsigned i=0;i<e[x].size();i++) {
 31         int &y=e[x][i].to;
 32         if(is_centroid[y]||y==par) continue;
 33         get_size(y,x);
 34         size[x]+=size[y];
 35         max=std::max(max,size[y]);
 36     }
 37     max=std::max(max,tree_size-size[x]);
 38     if(max<min_size) {
 39         min_size=max;
 40         centroid[centroid[0]]=x;
 41     }
 42 }
 43 void get_size2(const int x,const int par) {
 44     size[x]=1;
 45     for(unsigned i=0;i<e[x].size();i++) {
 46         int &y=e[x][i].to;
 47         if(is_centroid[y]||y==par) continue;
 48         get_size2(y,x);
 49         size[x]+=size[y];
 50     }
 51 }
 52 int l,u;
 53 inline bool cmp(const Edge a,const Edge b) {
 54     return size[a.to]<size[b.to];
 55 }
 56 void get_centroid(const int x,const int sz) {
 57     if(sz<l) return;
 58     tree_size=sz;
 59     min_size=inf;
 60     centroid[0]++;
 61     get_size(x,0);
 62     is_centroid[centroid[centroid[0]]]=true;
 63     int &now_centroid=centroid[centroid[0]];
 64     get_size2(now_centroid,0);
 65     std::sort(e[now_centroid].begin(),e[now_centroid].end(),cmp);
 66     for(unsigned i=0;i<e[now_centroid].size();i++) {
 67         int &y=e[now_centroid][i].to;
 68         if(is_centroid[y]) continue;
 69         get_centroid(y,size[y]);
 70     }
 71 }
 72 int max_depth,tmax_depth;
 73 double max[V],tmax[V];
 74 double m;
 75 void get_max(const int x,const int par,const int dep,const double dis) {
 76     if(dep>tmax_depth) {
 77         tmax_depth++;
 78         tmax[dep]=dis-m*dep;
 79     }
 80     else {
 81         tmax[dep]=std::max(tmax[dep],dis-m*dep);
 82     }
 83     for(unsigned i=0;i<e[x].size();i++) {
 84         int &y=e[x][i].to;
 85         if(is_centroid[y]||y==par) continue;
 86         get_max(y,x,dep+1,dis+e[x][i].w);
 87     }
 88 }
 89 int n;
 90 std::deque<int> q;
 91 inline bool check_subtree(const int x) {
 92     max_depth=0;
 93     for(unsigned i=0;i<e[x].size();i++) {
 94         int &y=e[x][i].to;
 95         if(is_centroid[y]) continue;
 96         tmax_depth=0;
 97         get_max(y,x,1,e[x][i].w);
 98         q.clear();
 99         for(int i=0,j=max_depth;i<=tmax_depth;i++) {
100             while((i+j)>u) j--;
101             while((i+j)>=l) {
102                 while(!q.empty()&&max[q.back()]<=max[j]) q.pop_back();
103                 q.push_back(j);
104                 j--;
105             }
106             while(!q.empty()&&(q.front()+i)>u) q.pop_front();
107             if(!q.empty()&&(max[q.front()]+tmax[i])>=0) {
108                 return true;
109             }
110         }
111         for(int i=1;i<=max_depth;i++) {
112             max[i]=std::max(max[i],tmax[i]);
113         }
114         for(int i=max_depth+1;i<=tmax_depth;i++) {
115             max[i]=tmax[i];
116         }
117         max_depth=std::max(max_depth,tmax_depth);
118     }
119     return false;
120 }
121 inline bool check() {
122     memset(is_centroid,0,sizeof is_centroid);
123     for(int i=1;i<=centroid[0];i++) {
124         is_centroid[centroid[i]]=true;
125         if(check_subtree(centroid[i])) return true; 
126     }
127     return false;
128 }
129 int main() {
130     unsigned $=1<<23;
131     char *_=(char*)malloc($)+$;
132     asm("mov %0,%%esp"::"r"(_));
133     n=getint(),l=getint(),u=getint();
134     for(int i=1;i<n;i++) {
135         int u=getint(),v=getint(),w=getint();
136         add_edge(u,v,w);
137         add_edge(v,u,w);
138     }
139     get_centroid(rand()%n+1,n);
140     double l=0,r=1e6;
141     while(l+eps<r) {
142         m=(l+r)/2;
143         (check()?l:r)=m;
144     } 
145     printf("%.3f\n",l);
146     return 0;
147 }

 

posted @ 2017-09-05 18:50  skylee03  阅读(206)  评论(0编辑  收藏  举报