zoukankan      html  css  js  c++  java
  • 【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<<'
    ';
    	}
    }
    
  • 相关阅读:
    mysql in 的两种使用方法
    Cocos2d-x游戏中默认的AndroidManifest.xml的解析
    UVA 11551
    本周游戏体验:卧虎藏龙
    Android.mk各种文件编译汇总
    hdu 寒冰王座
    树的专题整理(二)
    leetcode 题解 || Swap Nodes in Pairs 问题
    接上SQL SERVER的锁机制(一)——概述(锁的种类与范围)
    SQL SERVER的锁机制(一)——概述(锁的种类与范围)
  • 原文地址:https://www.cnblogs.com/stargazer-cyk/p/11145630.html
Copyright © 2011-2022 走看看