首页 > 代码库 > 2151: 种树 - BZOJ

2151: 种树 - BZOJ

Description

A城市有一个巨大的圆形广场,为了绿化环境和净化空气,市政府决定沿圆形广场外圈种一圈树。园林部门得到指令后,初步规划出n个种树的位置,顺时针编号1到n。并且每个位置都有一个美观度Ai,如果在这里种树就可以得到这Ai的美观度。但由于A城市土壤肥力欠佳,两棵树决不能种在相邻的位置(i号位置和i+1号位置叫相邻位置。值得注意的是1号和n号也算相邻位置!)。最终市政府给园林部门提供了m棵树苗并要求全部种上,请你帮忙设计种树方案使得美观度总和最大。如果无法将m棵树苗全部种上,给出无解信息。
Input

输入的第一行包含两个正整数n、m。第二行n个整数Ai。
Output

输出一个整数,表示最佳植树方案可以得到的美观度。如果无解输出“Error!”,不包含引号。
Sample Input
【样例输入1】
7 3
1 2 3 4 5 6 7
【样例输入2】
7 4
1 2 3 4 5 6 7

Sample Output
【样例输出1】
15

【样例输出2】
Error!
【数据规模】
对于全部数据:m<=n;
-1000<=Ai<=1000
N的大小对于不同数据有所不同:
数据编号 N的大小 数据编号 N的大小
1 30 11 200
2 35 12 2007
3 40 13 2008
4 45 14 2009
5 50 15 2010
6 55 16 2011
7 60 17 2012
8 65 18 199999
9 200 19 199999
10 200 20 200000

 

看wikioi的题解完全没有看懂

于是问了群里的人,结果告诉我是费用流优化

搞了半天总算懂了

首先我们把它拆成链,因为这样我们就好做了,我们只要算两遍就行了,一个是[1,n-1](表示n不取)一个是[2,n](表示1不取)

然后构费用流的图(有点奇葩......)

然后跑费用流就行了

但是显然不能跑费用流,承受不了

所以我们模拟费用流

假设我们选了点2(因为费用最大),然后增广后,残留网络是这样的

第1,2,3条路都没了

但是我们可以走从1到2到3,即多了一条路,费用为a[1]+a[3]-a[2]

我们也可以分析出只多出了这条路,其他的路都是没有用的

因为a[2]>=a[1],所以我们不可能从1走到2再走到S,所以没有别的路了

所以对于这种情况我们就用a[pre[i]]+a[next[i]]-a[i]代替a[i],然后删除pre[i]和next[i]

还有一种情况就是i是两端

这种情况想一想就知道了,端点是最大的那么就选端点,然后删掉在端点的那两个值就行了

所以我们用堆维护最大值,做m次就行了

  1 const
  2     maxn=200010;
  3 var
  4     q,h,a,b,pre,next:array[0..maxn]of longint;
  5     n,m,tot:longint;
  6 
  7 function max(x,y:longint):longint;
  8 begin
  9     if x>y then exit(x);
 10     exit(y);
 11 end;
 12 
 13 procedure swap(var x,y:longint);
 14 var
 15     t:longint;
 16 begin
 17     t:=x;x:=y;y:=t;
 18 end;
 19 
 20 procedure up(x:longint);
 21 var
 22     i:longint;
 23 begin
 24     while x>1 do
 25       begin
 26         i:=x>>1;
 27         if b[q[x]]>b[q[i]] then
 28           begin
 29             swap(q[x],q[i]);
 30             h[q[x]]:=x;
 31             h[q[i]]:=i;
 32             x:=i;
 33           end
 34         else break;
 35       end;
 36 end;
 37 
 38 procedure down(x:longint);
 39 var
 40     i:longint;
 41 begin
 42     i:=x<<1;
 43     while i<=tot do
 44       begin
 45         if (i<tot) and (b[q[i+1]]>b[q[i]]) then inc(i);
 46         if b[q[i]]>b[q[x]] then
 47           begin
 48             swap(q[x],q[i]);
 49             h[q[x]]:=x;
 50             h[q[i]]:=i;
 51             x:=i;
 52             i:=x<<1;
 53           end
 54         else break;
 55       end;
 56 end;
 57 
 58 procedure insert(x:longint);
 59 begin
 60     inc(tot);
 61     h[x]:=tot;
 62     q[tot]:=x;
 63     up(tot);
 64 end;
 65 
 66 procedure delete(x:longint);
 67 begin
 68     if x=0 then exit;
 69     b[q[x]]:=maxlongint;
 70     up(x);
 71     swap(q[1],q[tot]);
 72     h[q[1]]:=1;
 73     h[q[tot]]:=tot;
 74     dec(tot);
 75     down(1);
 76 end;
 77 
 78 function f(l,r:longint):longint;
 79 var
 80     i,u,v,t:longint;
 81 begin
 82     f:=0;
 83     tot:=0;
 84     for i:=l to r do
 85       begin
 86         b[i]:=a[i];
 87         insert(i);
 88         pre[i]:=i-1;
 89         next[i]:=i+1;
 90       end;
 91     pre[l]:=0;
 92     next[r]:=0;
 93     for i:=1 to m do
 94       begin
 95         t:=q[1];
 96         inc(f,b[t]);
 97         u:=pre[t];
 98         v:=next[t];
 99         if (u<>0) and (v<>0) then
100           begin
101             b[t]:=b[u]+b[v]-b[t];
102             pre[t]:=pre[u];
103             next[t]:=next[v];
104             next[pre[t]]:=t;
105             pre[next[t]]:=t;
106             down(h[t]);
107           end
108         else
109           begin
110             if u<>0 then next[pre[u]]:=0;
111             if v<>0 then pre[next[v]]:=0;
112             delete(h[t]);
113           end;
114         delete(h[u]);
115         delete(h[v]);
116       end;
117 end;
118 
119 procedure main;
120 var
121     i:longint;
122 begin
123     read(n,m);
124     if m*2>n then
125     begin
126       writeln(Error!);
127       exit;
128     end;
129     for i:=1 to n do
130       read(a[i]);
131     writeln(max(f(1,n-1),f(2,n)));
132 end;
133 
134 begin
135     main;
136 end.
View Code