把博客园图标替换成自己的图标
把博客园图标替换成自己的图标end

【BZOJ4367】[IOI2014] holiday假期(决策单调性+主席树)

点此看题面

  • \(n\)个城市,每个城市有一个价值\(a_i\)
  • \(st\)出发,花\(d\)天时间去游览,每天你可以走到一个相邻城市,或是访问所在城市(之前不能被访问过)获得当前城市的价值。
  • 求能获得的最大总价值。
  • \(n\le10^5,d\le2.5\times10^5\)

决策单调性

考虑我们不浪费任何步数的策略只有两种:

  • 向左走若干步(可以为零),走回起点,然后向右走。
  • 向右走若干步(可以为零),走回起点,然后向左走。

向左走和向右走的部分是相对独立的,所以我们实际上只要求出四个值:\(f1_x\)表示向左走\(x\)天能得到的最大代价,\(f2_x\)表示向左走\(x\)天并且回到起点的最大代价,\(f3_x\)表示向右走\(x\)天能得到的最大代价,\(f4_x\)表示向右走\(x\)天并且回到起点的最大代价。

\(f1_x\)的转移为例,我们可以枚举走到的位置\(p\),然后只要把\(x\)减去走到\(p\)的天数,剩余的天数肯定尽可能访问这段区间内价值大的那些节点,只要用主席树询问区间前\(k\)大之和即可。

显然随着\(x\)的增加,\(p\)的移动具有单调性,可以直接分治决策单调性。

要求最优的答案,直接枚举向左走的天数,得到:

\[t=\max\{f1_i+f4_{d-i},f2_i+f3_{d-i}\} \]

代码:\(O(nlog^2n)\)

#include<bits/stdc++.h>
#define Tp template<typename Ty>
#define Ts template<typename Ty,typename... Ar>
#define Reg register
#define RI Reg int
#define Con const
#define CI Con int&
#define I inline
#define W while
#define N 100000
#define D 250000
#define LL long long
using namespace std;
int n,st,d,Rt[N+5],a[N+5],dc,dv[N+5];
namespace FastIO
{
	#define FS 100000
	#define tc() (FA==FB&&(FB=(FA=FI)+fread(FI,1,FS,stdin),FA==FB)?EOF:*FA++)
	char oc,FI[FS],*FA=FI,*FB=FI;
	Tp I void read(Ty& x) {x=0;W(!isdigit(oc=tc()));W(x=(x<<3)+(x<<1)+(oc&15),isdigit(oc=tc()));}
	Ts I void read(Ty& x,Ar&... y) {read(x),read(y...);}
}using namespace FastIO;
class ChairmanTree
{
	private:
		#define PT CI l=1,CI r=dc
		#define LT l,mid
		#define RT mid+1,r
		int Nt;struct node {LL G;int Sz,S[2];}O[N*30];
	public:
		I void A(int& rt,CI x,PT)//单点修改
		{
			if(O[++Nt]=O[rt],++O[rt=Nt].Sz,O[rt].G+=dv[x],l==r) return;
			RI mid=l+r>>1;x<=mid?A(O[rt].S[0],x,LT):A(O[rt].S[1],x,RT);
		}
		I LL Q(CI A,CI B,CI k,PT)//区间第k大,主席树上二分
		{
			if(l==r) return 1LL*dv[l]*k;RI mid=l+r>>1,t=O[O[B].S[1]].Sz-O[O[A].S[1]].Sz;
			return t>=k?Q(O[A].S[1],O[B].S[1],k,RT):Q(O[A].S[0],O[B].S[0],k-t,LT)+O[O[B].S[1]].G-O[O[A].S[1]].G;
		}
}C;
LL f1[D+5];I void Solve1(CI l=2,CI r=d,CI L=st+1,CI R=min(st+d,n))//分治决策单调性求f1
{
	#define C1(x) C.Q(Rt[st],Rt[x],min(x-st,mid-(x-st)))
	if(l>r) return;RI mid=l+r>>1,p=L;LL o=C1(p),t;
	for(RI i=L+1;i<=R&&mid-(i-st)>=0;++i) (t=C1(i))>o&&(p=i,o=t);
	f1[mid]=o,Solve1(l,mid-1,L,p),Solve1(mid+1,r,p,R);
}
LL f2[D+5];I void Solve2(CI l=0,CI r=d,CI L=st,CI R=min(st+d/2,n))//分治决策单调性求f2
{
	#define C2(x) C.Q(Rt[st-1],Rt[x],min(x-st+1,mid-2*(x-st)))
	if(l>r) return;RI mid=l+r>>1,p=L;LL o=C2(p),t;
	for(RI i=L+1;i<=R&&mid-2*(i-st)>=0;++i) (t=C2(i))>o&&(p=i,o=t);
	f2[mid]=o,Solve2(l,mid-1,L,p),Solve2(mid+1,r,p,R);
}
LL f3[D+5];I void Solve3(CI l=2,CI r=d,CI L=max(st-d,1),CI R=st-1)//分治决策单调性求f3
{
	#define C3(x) C.Q(Rt[x-1],Rt[st-1],min(st-x,mid-(st-x)))
	if(l>r) return;RI mid=l+r>>1,p=R;LL o=C3(p),t;
	for(RI i=R-1;i>=L&&mid-(st-i)>=0;--i) (t=C3(i))>o&&(p=i,o=t);
	f3[mid]=o,Solve3(l,mid-1,p,R),Solve3(mid+1,r,L,p);
}
LL f4[D+5];I void Solve4(CI l=0,CI r=d,CI L=max(st-d/2,1),CI R=st)//分治决策单调性求f4
{
	#define C4(x) C.Q(Rt[x-1],Rt[st],min(st-x+1,mid-2*(st-x)))
	if(l>r) return;RI mid=l+r>>1,p=R;LL o=C4(p),t;
	for(RI i=R-1;i>=L&&mid-2*(st-i)>=0;--i) (t=C4(i))>o&&(p=i,o=t);
	f4[mid]=o,Solve4(l,mid-1,p,R),Solve4(mid+1,r,L,p);
}
int main()
{
	RI i;for(read(n,st,d),++st,i=1;i<=n;++i) read(a[i]),dv[i]=a[i];sort(dv+1,dv+n+1);
	for(dc=unique(dv+1,dv+n+1)-dv-1,i=1;i<=n;++i) Rt[i]=Rt[i-1],C.A(Rt[i],lower_bound(dv+1,dv+dc+1,a[i])-dv);//建出主席树
	st^n&&(Solve1(),0),Solve2(),st^1&&(Solve3(),0),Solve4();LL t=0;
	for(i=0;i<=d;++i) t=max(t,max(f1[i]+f4[d-i],f2[i]+f3[d-i]));return printf("%lld\n",t),0;//求出最优答案
}
posted @ 2021-04-07 18:38  TheLostWeak  阅读(64)  评论(0编辑  收藏  举报