[BZOJ5308][ST表]ZJOI2018:胖

版权声明:虽然博主很菜,但是还是请注明出处(我觉得应该没人偷我的博客) https://blog.csdn.net/qq_43346903/article/details/88101668

BZOJ5308

因为城墙是一条直线,所以很容易看出我们只需要考虑城堡到城墙的路
那么关键是求出一条城堡到城墙的路的贡献
把一条路的终点向左右走的边界拓展出来,然后用ST表辅助查询就好了

Code:

#include<bits/stdc++.h>
#define ll long long
using namespace std;
inline int read(){
	int res=0,f=1;char ch=getchar();
	while(!isdigit(ch)) {if(ch=='-') f=-f;ch=getchar();}
	while(isdigit(ch)) {res=(res<<1)+(res<<3)+(ch^48);ch=getchar();}
	return res*f;
}
const int N=2e5+5;
const ll INF=1e18;
int n,m,t,k,lg[N];
ll d1[N],d2[N],len[N],d[N];
ll mx[N][20],mn[N][20];
struct E{int a;ll len;E(){}E(int _a,ll _len):a(_a),len(_len){}}e[N];
inline bool operator < (const E &a,const E &b){return a.a<b.a;}
inline int maxx(int a,int b){if(d1[a]==d1[b]) return a>b?a:b; return d1[a]>d1[b]?a:b;}
inline int minn(int a,int b){if(d2[a]==d2[b]) return a<b?a:b; return d2[a]<d2[b]?a:b;}
inline void init(){
	sort(e+1,e+k+1);
	for(int i=1;i<=k;i++){
		d1[i]=d[e[i].a]-e[i].len,d2[i]=d[e[i].a]+e[i].len;
		mx[i][0]=mn[i][0]=i;
	}
	for(int i=1;(1<<i)<=k;i++)
		for(int j=1;j+(1<<i)-1<=k;j++){
			mx[j][i]=maxx(mx[j][i-1],mx[j+(1<<(i-1))][i-1]);
			mn[j][i]=minn(mn[j][i-1],mn[j+(1<<(i-1))][i-1]);
		}
}
inline int getmx(int l,int r){
	int o=lg[r-l+1];
	return maxx(mx[l][o],mx[r-(1<<o)+1][o]);
}
inline int getmn(int l,int r){
	int o=lg[r-l+1];
	return minn(mn[l][o],mn[r-(1<<o)+1][o]);
}
inline int high(int a,int b,int p){
	ll resa=e[a].len+abs(d[p]-d[e[a].a]);
	ll resb=e[b].len+abs(d[p]-d[e[b].a]);
	if(resa!=resb) return resa<resb?a:b;
	if(abs(e[a].a-p)!=abs(e[b].a-p))
		return abs(e[a].a-p)<abs(e[b].a-p)?a:b;
	return a<b?a:b;
}
inline bool check(int p,int kk){
	int res=abs(e[kk].a-p),b=kk;
	int l=lower_bound(e+1,e+k+1,E(p-res,0))-e;
	int r=upper_bound(e+1,e+k+1,E(p+res,0))-e-1;
	int mid=upper_bound(e+1,e+k+1,E(p,0))-e-1;
	if(l<=mid) b=high(b,getmx(l,mid),p);
	if(r>mid) b=high(b,getmn(mid+1,r),p);
	return b==kk;
}
inline ll solve(){
	ll ans=0;
	for(int i=1;i<=k;i++){
		int l=1,r=e[i].a,mid,L;
		while(l<r)
			if(check(mid=((l+r)>>1),i)) r=mid;
			else l=mid+1;
		L=l,l=e[i].a,r=n;
		while(l<r)
			if(check(mid=((l+r+1)>>1),i)) l=mid;
			else r=mid-1;
		ans+=(r-L+1);
	}
	return ans;
}
int main(){
	for(int i=2;i<N;i++) lg[i]=lg[i>>1]+1;
	n=read(),m=read();
	for(int i=2;i<=n;i++)
		d[i]=read(),d[i]+=d[i-1];
	while(m--){
		k=read();
		for(int i=1;i<=k;i++)
			e[i].a=read(),e[i].len=read();
		init();
		cout<<solve()<<"\n";
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_43346903/article/details/88101668