• 【BZOJ5308】[ZJOI2018]胖(模拟,ST表,二分)


    【BZOJ5308】[ZJOI2018]胖(模拟,ST表,二分)

    题面

    BZOJ
    洛谷

    题解

    首先发现每条(0)出发的边都一定会更新到底下的一段区间的点。
    考虑存在一条(0 ightarrow x)的边,我们来求解其可以影响的区间([L,R]),显然(Lle xle R)
    两侧分开考虑,以左边举例。
    二分一个(L)。如果这个(L)可行,即不存在一条边(0 ightarrow y),满足(W_{0 ightarrow x}+Dis(L,x)ge W_{0 ightarrow y}+Dis(L,y)),且(abs(y-L)le abs(x-L))
    也就是要么(x)出发能够更新最短路,要么就是(x)(L)更近,所以先被(x)的路径更新了一次。
    那么对于二分出来的(L),令(len=|x-L|),如果在([L-len,L+len])区间内存在一个点能够更新出更小的距离则当前(L)不可行。(R)同理。
    然后大力(ST)表二分一下就好了。
    注意一下如果一个点可以同时被多个点更新的时候,一定要确定好一个顺序关系,使得最终计算出来的结果不重不漏。

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    using namespace std;
    #define ll long long
    #define MAX 200200
    inline int read()
    {
    	int x=0;bool t=false;char ch=getchar();
    	while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
    	if(ch=='-')t=true,ch=getchar();
    	while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
    	return t?-x:x;
    }
    int n,Q,k,lg[MAX];
    ll w[MAX],v1[MAX],v2[MAX];
    ll mn[20][MAX],mx[20][MAX];
    struct Line{int x,w;}a[MAX];
    bool operator<(Line a,Line b){return a.x<b.x;}
    int Max(int x,int y)
    {
    	if(v1[x]!=v1[y])return v1[x]>v1[y]?x:y;
    	if(a[x].x!=a[y].x)return a[x].x>a[y].x?x:y;
    	return x<y?x:y;
    }
    int Min(int x,int y)
    {
    	if(v2[x]!=v2[y])return v2[x]<v2[y]?x:y;
    	if(a[x].x!=a[y].x)return a[x].x<a[y].x?x:y;
    	return x<y?x:y;
    }
    void pre()
    {
    	for(int i=1;i<=k;++i)
    		v1[i]=w[a[i].x]-a[i].w,v2[i]=w[a[i].x]+a[i].w;
    	for(int i=1;i<=k;++i)mx[0][i]=mn[0][i]=i;
    	for(int j=1;j<=lg[k];++j)
    		for(int i=1;i+(1<<j)-1<=k;++i)
    		{
    			mx[j][i]=Max(mx[j-1][i],mx[j-1][i+(1<<(j-1))]);
    			mn[j][i]=Min(mn[j-1][i],mn[j-1][i+(1<<(j-1))]);
    		}
    }
    ll RMQ_mx(int l,int r)
    {
    	int k=lg[r-l+1];
    	return Max(mx[k][l],mx[k][r-(1<<k)+1]);
    }
    ll RMQ_mn(int l,int r)
    {
    	int k=lg[r-l+1];
    	return Min(mn[k][l],mn[k][r-(1<<k)+1]);
    }
    bool check(int x,int l,int y)
    {
    	int p=lower_bound(&a[1],&a[k+1],(Line){y-l,0})-a;
    	int q=upper_bound(&a[1],&a[k+1],(Line){y+l,0})-a-1;
    	int r=lower_bound(&a[1],&a[k+1],(Line){y,0})-a;
    	if(r<=q)
    	{
    		int pos=RMQ_mn(r,q);ll V=abs(w[a[x].x]-w[y])+a[x].w;
    		if(v2[pos]-w[y]<V||(v2[pos]-w[y]==V&&abs(a[pos].x-y)<abs(a[x].x-y))
    		   ||(v2[pos]-w[y]==V&&abs(a[pos].x-y)==abs(a[x].x-y)&&pos<x))
    			return false;
    	}
    	if(p<r)
    	{
    		int pos=RMQ_mx(p,r-1);ll V=abs(w[a[x].x]-w[y])+a[x].w;
    		if(w[y]-v1[pos]<V||(w[y]-v1[pos]==V&&abs(a[pos].x-y)<abs(y-a[x].x))
    		   ||(w[y]-v1[pos]==V&&abs(a[pos].x-y)==abs(a[x].x-y)&&pos<x))
    			return false;
    	}
    	return true;
    }
    int GetL(int x)
    {
    	int l=1,r=a[x].x,ret=a[x].x;
    	while(l<=r)
    	{
    		int mid=(l+r)>>1;
    		if(check(x,a[x].x-mid,mid))ret=mid,r=mid-1;
    		else l=mid+1;
    	}
    	return ret;
    }
    int GetR(int x)
    {
    	int l=a[x].x,r=n,ret=a[x].x;
    	while(l<=r)
    	{
    		int mid=(l+r)>>1;
    		if(check(x,mid-a[x].x,mid))ret=mid,l=mid+1;
    		else r=mid-1;
    	}
    	return ret;
    }
    ll Solve()
    {
    	k=read();for(int i=1;i<=k;++i)a[i].x=read(),a[i].w=read();
    	sort(&a[1],&a[k+1]);
    	pre();ll ans=0;
    	for(int i=1;i<=k;++i)
    	{
    		ans+=GetR(i)-GetL(i)+1;
    	}
    	return ans;
    }
    int main()
    {
    	n=read();Q=read();
    	for(int i=2;i<=n;++i)lg[i]=lg[i>>1]+1;
    	for(int i=2;i<=n;++i)w[i]=read()+w[i-1];
    	while(Q--)printf("%lld
    ",Solve());
    	return 0;
    }
    
  • 相关阅读:
    SQL SEREVR IO
    INTEL
    windows performance
    The DiskSpd Storage Performance Tool
    machine Learning
    NOSQL
    X64 Deep Dive
    Debugging and performance,ETW
    Disk Performance
    WCF transport-and-message-security
  • 原文地址:https://www.cnblogs.com/cjyyb/p/10414922.html
Copyright © 2020-2023  润新知