【BZOJ5307】【ZJOI2018】—胖(ST表+二分)

传送门

贝尔福特曼是什么算法?那不应该是spafspaf吗?

考虑对一个点xx总共可以松弛多少个点
显然xx可以松弛是一段连续的区间[L,R][L,R]
发现不好维护可以松弛到哪里
考虑二分一个位置midmid,判定是否能被松弛

假设二分一个mid(mid>x)mid(mid>x)
显然会影响xxmidmid松弛只有可能是[x,2xmid][x,2*x-mid]这段区间的关键点
如果存在点yy满足disy,mid+a[y]disx,mid+a[x]dis_{y,mid}+a[y]le dis_{x,mid}+a[x]
若记一个前缀距离和即sumy+a[y]sumx+a[x]sum_y+a[y]le sum_{x}+a[x]
那考虑对于每一个关键点维护sumx+a[x]sum_x+a[x],那只需要查找在区间是否有更小的数

对关键点建一个stst表就可以了
注意二分是在原序列上二分,而stst表是在kk个关键点上
所以每次stst表要先二分在哪2个关键点之间
复杂度O(nlog2n)O(nlog^2n)
有点卡常

#include<bits/stdc++.h>
using namespace std;
const int RLEN=1<<18|1;
inline char nc() {
	static char ibuf[RLEN],*ib,*ob;
	(ib==ob) && (ob=(ib=ibuf)+fread(ibuf,1,RLEN,stdin));
	return (ib==ob) ? -1 : *ib++;
}
inline int read() {
	char ch=nc(); int i=0,f=1;
	while(!isdigit(ch)) {if(ch=='-')f=-1; ch=nc();}
	while(isdigit(ch)) {i=(i<<1)+(i<<3)+ch-'0'; ch=nc();}
	return i*f;
}
#define ll long long
#define re register
const int N=200005;
const ll inf=1e18;
struct node{
	int p;ll k;
	node(int _p=0,ll _k=0):p(_p),k(_k){}
	friend inline bool operator <(const node &a,const node &b){
		return a.p<b.p;
	}
}a[N];
int n,m,k,lg[N],val[N];
ll ans,dis[N];
struct ST{
	ll st[20][N];
	inline void init(){
		for(re int i=1;i<=k;++i)st[0][i]=a[i].k;
		for(re int j=1;j<=lg[k];++j){
			for(re int i=1;i+(1<<j)-1<=k;++i)
				st[j][i]=min(st[j-1][i],st[j-1][i+(1<<(j-1))]);
		}
	}
	inline ll query(int l,int r){
		l=max(l,1),r=min(r,n);
		l=lower_bound(a+1,a+k+1,node(l))-a;
		r=upper_bound(a+1,a+k+1,node(r))-a-1;
		if(l>r)return inf;
		int t=lg[r-l+1];
		return min(st[t][l],st[t][r-(1<<t)+1]);
	}
}L,R;
inline bool check1(int l,int r){
	if(l==r)return 1;
	ll r1=L.query(2*l-r+1,l)+dis[l];
	ll r2=R.query(l,r-1)-dis[l];
	ll r3=R.query(r,r)-dis[l];
	if(r1<=r3||r2<=r3)return false;
	if(2*l-r>=1)return L.query(2*l-r,2*l-r)+dis[l]>=r3;
	return true;
}
inline bool check2(int l,int r){
	if(l==r)return 1;
	ll r1=R.query(r,2*r-l-1)-dis[r];
	ll r2=L.query(l+1,r)+dis[r];
	ll r3=L.query(l,l)+dis[r];
	if(r1<=r3||r2<=r3)return false;
	if(2*r-l<=n)return R.query(2*r-l,2*r-l)-dis[r]>r3;
	return true;
}
inline int solve1(int p){
	int l=1,r=p,mid,res=0;
	while(l<=r){
		mid=(l+r)>>1;
		if(check1(mid,p))r=mid-1,res=mid;
		else l=mid+1;
	}
	return res;
}
inline int solve2(int p){
	int l=p,r=n,mid,res=0;
	while(l<=r){
		mid=(l+r)>>1;
		if(check2(p,mid))l=mid+1,res=mid;
		else r=mid-1;
	}
	return res;
}
int main(){
	n=read(),m=read();
	for(re int i=2;i<=n;++i)lg[i]=lg[i>>1]+1;
	for(re int i=2;i<=n;++i)val[i]=read(),dis[i]=dis[i-1]+val[i];
	while(m--){
		k=read();
		for(re int i=1;i<=k;++i)a[i].p=read(),a[i].k=read();
		sort(a+1,a+k+1),ans=0;
		for(re int i=1;i<=k;++i)a[i].k-=dis[a[i].p];L.init();
		for(re int i=1;i<=k;++i)a[i].k+=2*dis[a[i].p];R.init();
		for(re int i=1;i<=k;++i)ans+=solve2(a[i].p)-solve1(a[i].p)+1;
		cout<<ans<<'
';
	}
}
原文地址:https://www.cnblogs.com/stargazer-cyk/p/11145630.html