2019.03.04【ZJOI2018】【洛谷P4501】【BZOJ5308】胖(ST表)(二分答案)

版权声明:转载请声明出处,谢谢配合。 https://blog.csdn.net/zxyoi_dreamer/article/details/88140895

BZOJ传送门

洛谷传送门


解析:

ZJOI2018对我现阶段而言唯一一道可做的题。(剩下全是神仙题做之前先%jiry_2)

我们发现这个图长得很有特点,而且Bellman-Ford第一步肯定是更新直接连接的那些节点。然后再在链上扩展。

现在考虑一个点与 0 0 有边的点 u u ,它能够更新的显然是包含它的一个连续区间,我们需要考虑求出这个区间的左右端点 l , r l,r ,那么就能够得到它更新的区间长度就是 r l + 1 r-l+1

u u 能够更新 v v 的条件也很显然,设 l = u v l=|u-v| ,则 u u 应该是 [ v l , v + l ] [v-l,v+l] 中的特殊点中到 v v 最近的。当然我们还要考虑相等距离取坐标差小的问题。

显然我们可以根据 u u v v 的哪边进行分类讨论。设 v a l u val_u 0 0 u u 的距离, d i s t u dist_u 是链上 u u 1 1 的距离,用于差分。

d i s ( u , v ) = { v a l u u + v u v v a l u + u v v < u dis(u,v)=\left\{\begin{aligned}val_u-u+v &&u \leq v\\val_u+u-v &&v< u\end{aligned}\right.

维护两个ST表就行了。

不开O2的话就不要用lower_bound和upper_bound了,手写吧。

不过开了O2就没什么区别了。


代码:

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define re register
#define gc get_char
#define cs const

namespace IO{
	inline char get_char(){
		static cs int Rlen=1<<20|1;
		static char buf[Rlen],*p1,*p2;
		return (p1==p2)&&(p2=(p1=buf)+fread(buf,1,Rlen,stdin),p1==p2)?EOF:*p1++;
	}
	
	inline int getint(){
		re char c;
		while(!isdigit(c=gc()));re int num=c^48;
		while(isdigit(c=gc()))num=(num+(num<<2)<<1)+(c^48);
		return num;
	}
}
using namespace IO;

cs int N=2e5+5,logN=18;

int n,m,K;

struct edge{
	int to,dis;
	bool operator<(cs edge &b)cs{
		return to<b.to;
	}
}e[N],tmp;

namespace ST{
	ll l[logN][N],r[logN][N];
	int logn[N];
	inline void init(){
		for(int re i=1;i<=logn[K];++i){
			for(int re j=1;(1<<i)+j-1<=K;++j){
				l[i][j]=min(l[i-1][j],l[i-1][j+(1<<(i-1))]);
				r[i][j]=min(r[i-1][j],r[i-1][j+(1<<(i-1))]);
			}
		}
	}
	
	inline ll query_l(cs int &L,cs int &R){
		int len=logn[R-L+1];
		return min(l[len][L],l[len][R-(1<<len)+1]);
	}
	
	inline ll query_r(cs int &L,cs int &R){
		int len=logn[R-L+1];
		return min(r[len][L],r[len][R-(1<<len)+1]);
	}
	
	inline int lower_bound(cs int &a){
		int l=1,r=K+1;
		while(l<r){
			int mid=(l+r)>>1;
			if(e[mid].to<a)l=mid+1;
			else r=mid;
		}
		return l;
	}
	
	inline int upper_bound(cs int &a){
		int l=1,r=K+1;
		while(l<r){
			int mid=(l+r)>>1;
			if(e[mid].to<=a)l=mid+1;
			else r=mid;
		} 
		return l;
	}
	
	inline ll Ql(int u,int v){
		u=max(1,u),v=min(v,n);
		u=lower_bound(u);
		v=upper_bound(v)-1;
		if(u>v)return 0x3f3f3f3f3f3f3f3f;
		return query_l(u,v);
	}
	
	inline ll Qr(int u,int v){
		u=max(1,u),v=min(v,n);
		u=lower_bound(u);
		v=upper_bound(v)-1;
		if(u>v)return 0x3f3f3f3f3f3f3f3f;
		return query_r(u,v);
	}
}

ll dist[N],ans;

inline bool check_L(int u,int pos){
	if(u==pos)return true;
	ll mpt=ST::Qr(u,u)-dist[pos];
	ll d1=ST::Qr(pos,u-1)-dist[pos];
	ll d2=ST::Ql(2*pos-u+1,pos)+dist[pos];
	if(d1<=mpt||d2<=mpt)return false;
	if(2*pos-u>0)return ST::Ql(2*pos-u,2*pos-u)+dist[pos]>mpt;
	return true;
}

inline bool check_R(int u,int pos){
	if(u==pos)return true;
	ll mpt=ST::Ql(u,u)+dist[pos];
	ll d1=ST::Ql(u+1,pos)+dist[pos];
	ll d2=ST::Qr(pos,2*pos-u-1)-dist[pos];
	if(d1<=mpt||d2<=mpt)return false;
	if(2*pos-u<=n)return ST::Qr(2*pos-u,2*pos-u)-dist[pos]>=mpt;
	return true;
}

inline int find_L(int u){
	int l=1,r=u;
	while(l<r){
		int mid=(l+r)>>1;
		if(check_L(u,mid))r=mid;
		else l=mid+1;
	}
	return l;
}

inline int find_R(int u){
	int l=u,r=n,ans=u;
	while(l<=r){
		int mid=(l+r+1)>>1;
		if(check_R(u,mid))l=mid+1,ans=mid;
		else r=mid-1;
	}
	return ans;
}

signed main(){
	n=getint(),m=getint();
	for(int re i=2;i<=n;++i)ST::logn[i]=ST::logn[i>>1]+1;
	for(int re i=2;i<=n;++i)dist[i]=dist[i-1]+getint();
	while(m--){
		K=getint();
		for(int re i=1;i<=K;++i)e[i].to=getint(),e[i].dis=getint();
		sort(e+1,e+K+1);
		for(int re i=1;i<=K;++i){
			ST::l[0][i]=e[i].dis-dist[e[i].to];
			ST::r[0][i]=e[i].dis+dist[e[i].to];
		}
		ST::init();
		ans=0;
		for(int re i=1;i<=K;++i)
		ans+=find_R(e[i].to)-find_L(e[i].to)+1;
		cout<<ans<<'\n';
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/zxyoi_dreamer/article/details/88140895