zoukankan      html  css  js  c++  java
  • [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
    ",l);
    146     return 0;
    147 }
  • 相关阅读:
    Python_装饰器复习_30
    Python_每日习题_0002_个税计算
    linux-文件流4种读取方式
    Max Sum Plus Plus
    棋盘问题
    noip数学
    P3384 【模板】树链剖分
    P2419 [USACO08JAN]牛大赛Cow Contest
    poj3159 Candies(差分约束)
    小K的农场(差分约束)
  • 原文地址:https://www.cnblogs.com/skylee03/p/7481342.html
Copyright © 2011-2022 走看看