UVALive6900 Road Repair(树的点分治)

题目大概说一棵树,树边有费用和收益两个属性,求一条收益和最大的路径满足费用和不超过C。

树上任意两点的路径都可以看成是过某一个子树根的路径,显然树分治。

治的时候要解决的一个问题是,找到费用小于等于某个数且收益最大的值。

这个很容易想到用线段树,不过不想写线段树。。

想了想,想到可以先排序,从小到大去找,之前找到哪现在就继续从那儿开始找,这样最多也就遍历一遍待查找数组,具体看代码。

两次排序占大头,最后时间复杂度是O(nlog2n)。

WA了一次,因为只考虑了两端都过根的路径,忽略了一端点是根的路径。。之前写树分治也是因为这个WA。。

  1 #include<cstdio>
  2 #include<cstring>
  3 #include<algorithm>
  4 using namespace std;
  5 #define INF (1<<30)
  6 #define MAXN 22222
  7 struct Edge{
  8     int v,b,c,next;
  9 }edge[MAXN<<1];
 10 int NE,head[MAXN];
 11 void addEdge(int u,int v,int b,int c){
 12     edge[NE].v=v; edge[NE].b=b; edge[NE].c=c; edge[NE].next=head[u];
 13     head[u]=NE++;
 14 }
 15 bool vis[MAXN];
 16 int size[MAXN];
 17 void getsize(int u,int fa){
 18     size[u]=1;
 19     for(int i=head[u]; i!=-1; i=edge[i].next){
 20         int v=edge[i].v;
 21         if(v==fa || vis[v]) continue;
 22         getsize(v,u);
 23         size[u]+=size[v];
 24     }
 25 }
 26 int mm,cen;
 27 void getcen(int u,int fa,int &tot){
 28     int res=tot-size[u];
 29     for(int i=head[u]; i!=-1; i=edge[i].next){
 30         int v=edge[i].v;
 31         if(v==fa || vis[v]) continue;
 32         getcen(v,u,tot);
 33         res=max(res,size[v]);
 34     }
 35     if(res<mm){
 36         mm=res;
 37         cen=u;
 38     }
 39 }
 40 int getcen(int u){
 41     getsize(u,u);
 42     mm=INF;
 43     getcen(u,u,size[u]);
 44     return cen;
 45 }
 46 struct Rec{
 47     int b,c;
 48     bool operator<(const Rec &r)const{
 49         return c<r.c;
 50     }
 51 }ra[MAXN],rb[MAXN];
 52 int tot,an,bn;
 53 void dfs(int u,int fa,int benfit,int cost){
 54     rb[bn].b=benfit;
 55     rb[bn].c=cost;
 56     bn++;
 57     for(int i=head[u]; i!=-1; i=edge[i].next){
 58         int v=edge[i].v;
 59         if(v==fa || vis[v]) continue;
 60         dfs(v,u,benfit+edge[i].b,cost+edge[i].c);
 61     }
 62 }
 63 int ans;
 64 void conqur(int u){
 65     an=1;
 66     ra[0].b=0; ra[0].c=0;
 67     for(int i=head[u]; i!=-1; i=edge[i].next){
 68         int v=edge[i].v;
 69         if(vis[v]) continue;
 70         bn=0;
 71         dfs(v,v,edge[i].b,edge[i].c);
 72         sort(ra,ra+an);
 73         sort(rb,rb+bn);
 74         int pa=an-1,pb=0;
 75         while(pb<bn){
 76             int mx=-1;
 77             for(int j=pa; j>=0; --j){
 78                 if(ra[j].c+rb[pb].c<=tot){
 79                     if(mx<ra[j].b+rb[pb].b){
 80                         mx=ra[j].b+rb[pb].b;
 81                         pa=j;
 82                     }
 83                 }
 84             }
 85             if(mx==-1) break;
 86             ans=max(ans,mx);
 87             ++pb;
 88         }
 89         for(int j=0; j<bn; ++j){
 90             ra[an++]=rb[j];
 91         }
 92     }
 93 }
 94 void divide(int u){
 95     u=getcen(u);
 96     vis[u]=1;
 97     conqur(u);
 98     for(int i=head[u]; i!=-1; i=edge[i].next){
 99         int v=edge[i].v;
100         if(vis[v]) continue;
101         divide(v);
102     }
103 }
104 int main(){
105     int t,n,a,b,c,d;
106     scanf("%d",&t);
107     while(t--){
108         scanf("%d",&n);
109         NE=0;
110         memset(head,-1,sizeof(head));
111         for(int i=1; i<n; ++i){
112             scanf("%d%d%d%d",&a,&b,&c,&d);
113             addEdge(a,b,d,c);
114             addEdge(b,a,d,c);
115         }
116         scanf("%d",&tot);
117         ans=0;
118         memset(vis,0,sizeof(vis));
119         divide(1);
120         printf("%d
",ans);
121     }
122     return 0;
123 }
原文地址:https://www.cnblogs.com/WABoss/p/5443745.html