分治,函数式线段树,题解去问大神吧。。。
提交地址:http://uoj.ac/problem/29【似乎没有vjudge】
#include<cstdio>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#include "holiday.h"
#define c(x,y) tree[x].c[y]
#define Sum(x) tree[x].sum
#define Num(x) tree[x].num
const int MAXN = 100005,SIZE = 2200000 , MAXD = (MAXN<<1) + (MAXN>>1) + 5;
int n , nl ,st;long long ans = 0;
struct treenode{long long sum;int c[2],num;}tree[SIZE] = {0};
int tot = 0 , root[MAXN] = {0};
int w[MAXN] = {0} , *lixed ,lix[MAXN] = {0},fin[MAXN] = {0};
long long fw[2][MAXD] = {0},gw[2][MAXD] = {0};
inline void update(int x)
{Num(x) = Num(c(x,0)) + Num(c(x,1)) , Sum(x) = Sum(c(x,0)) + Sum(c(x,1));}
int build0(int ll,int rr)
{
int ret = ++tot ;
if(ll != rr)
{
int mid = (ll+rr)>>1;
if(ll<=mid){c(ret,0) = build0(ll,mid);}
if(mid<rr){c(ret,1) = build0(mid+1,rr);}
}
return ret;
}
int build1(int ki,int ll,int rr,int si)
{
int ret = ++tot;
if(ll == rr){Num(ret) = Num(si) + 1,Sum(ret) = Sum(si) + lix[ki];}
else
{
int mid = (ll+rr)>>1;bool i = (mid<ki);
if(i)c(ret,i) = build1(ki,mid+1,rr,c(si,i));
else c(ret,i) = build1(ki,ll,mid,c(si,i));
c(ret,i^1) = c(si,i^1); update(ret);
}
return ret;
}
void buildtree()
{
root[0] = build0(1,nl);
for(int i = 1; i <= n; i++)
root[i] = build1(fin[i],1,nl,root[i-1]);
return ;
}
long long ask(int r1,int r2,int k)
{
if(k < 0)return 0;
if(k >= Num(r2) - Num(r1)) return (Sum(r2) - Sum(r1));
long long ret = 0;
int num1; long long sum1;
int ll = 1, rr = nl , mid;
while(k)
{
if(ll == rr)
{ret += lix[ll]*k;break;}
num1 = Num(c(r2,1)) - Num(c(r1,1));
sum1 = Sum(c(r2,1)) - Sum(c(r1,1));
mid = (ll + rr)>>1;
if(k < num1)
{
r1 = c(r1,1), r2 = c(r2,1); ll = mid+1;
}
else
{
k -=num1; ret += sum1;
r1 = c(r1,0), r2 = c(r2,0); rr = mid;
}
}
return ret;
}
void right(int l,int r,int fl,int fr,int tag)
{
int mid = (l + r)>>1 ,fi = fl;
for(int i = fl; i <= fr; i++)
{
long long tmp = ask(root[st-1],root[i],mid - (i-st)*(tag+1));
if(tmp > fw[tag][mid]) {fi = i , fw[tag][mid] = tmp;}
}
if(l<mid)right(l,mid-1,fl,fi,tag);
if(mid<r)right(mid+1,r,fi,fr,tag);
}
void left(int l,int r,int gl,int gr,int tag)
{
int mid = (l + r)>>1 ,gi = gl;
for(int i = gl; i <= gr; i++)
{
long long tmp = ask(root[i-1],root[st-1],mid - (st-i)*(tag+1));
if(tmp > gw[tag][mid]) {gi = i , gw[tag][mid] = tmp;}
}
if(l<mid)left(l,mid-1,gi,gr,tag);
if(mid<r)left(mid+1,r,gl,gi,tag);
}
long long int findMaxAttraction(int n0, int st0, int d, int att[])
{
n = n0, st = st0 + 1;w[0] = 0;
for(int i = 0; i < n ; i++)w[i+1] = att[i];
for(int i = 1; i <= n ; i++)lix[i] = w[i];
std::sort(lix+1, lix+n+1);
lixed = std::unique(lix+1,lix+n+1);
nl = lixed - (lix+1);
for(int i = 1; i <= n ; i++)
fin[i] = std::lower_bound(lix+1,lix+nl+1,w[i]) - lix;
buildtree();
left(1,d,1,st-1,0);
left(1,d,1,st-1,1);
right(1,d,st,n,0);
right(1,d,st,n,1);
// ans = std::max(fw[0][d],fw[1][d]);
for(int i = 0 ; i <= d ; i++)
{
ans = std::max(ans,fw[1][i] + gw[0][d-i]);
ans = std::max(ans,gw[1][i] + fw[0][d-i]);
}
return ans;
}