• P4501 [ZJOI2018]胖


    题目

    P4501 [ZJOI2018]胖

    官方口中的送分题

    做法

    我们通过手玩(脑补),(a_i)所作的贡献(能更新的点)为:在(a_i)更新(forall x)更新前前没有其他点能把(x)更新到更优

    我们预处理出数组(dis[i])(1)号点走到(i)号点的未包含计划前的距离

    对于(x≤a[i]Longrightarrow edge[x]=-dis[x]+(l[i]+dis[a[i]])),对于(x≥a[i]Longrightarrow dis[x]+(l[i]-dis[a[i]]))

    能更新的范围显然是有单调性的,二分左右端点((st)表维护区间最小值判断),时间复杂度(O(nlogn^2))

    My complete code

    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<string>
    #include<algorithm>
    #include<cmath>
    using namespace std;
    typedef long long LL;
    const LL maxn=1e6,inf=1e17;
    inline LL Read(){
    	LL x(0),f(1);char c=getchar();
    	while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
    	while(c>='0'&&c<='9')x=(x<<3)+(x<<1)+c-'0',c=getchar();
    	return x*f;
    }
    LL n,q,K; LL dis[maxn];
    struct node{
    	LL p,l;
    	bool operator < (const node &b)const{
    		return p<b.p;
    	}
    }a[maxn];
    struct ST{
    	LL st1[maxn][20],st2[maxn][20];
    	inline void Init(){
    		for(LL i=1;i<=K;++i)
    		    st1[i][0]=a[i].l-dis[a[i].p],st2[i][0]=a[i].l+dis[a[i].p];
    		for(LL j=1;j<=18;++j)
    		    for(LL i=1;i<=K;++i)
    		        st1[i][j]=min(st1[i][j-1],st1[i+(1<<j-1)][j-1]),
    		        st2[i][j]=min(st2[i][j-1],st2[i+(1<<j-1)][j-1]);
    	}
    	inline LL Getl(LL x){
    		node tmp; tmp.p=x;
    		return lower_bound(a+1,a+1+K,tmp)-a;
    	}
    	inline LL Getr(LL x){
    		node tmp; tmp.p=x;
    		return upper_bound(a+1,a+1+K,tmp)-a-1;
    	}
    	inline LL Query1(LL l,LL r){
    		if(l>r) swap(l,r); l=max(1ll,l),r=min(n,r);
    		l=Getl(l),r=Getr(r);
    		if(l>r) return inf;
    		LL lg=log2(r-l+1);
    		return min(st1[l][lg],st1[r-(1<<lg)+1][lg]);
    	}
    	inline LL Query2(LL l,LL r){
    		if(l>r) swap(l,r); l=max(1ll,l),r=min(n,r);
    		l=Getl(l),r=Getr(r);
    		if(l>r) return inf;
    		LL lg=log2(r-l+1);
    		return min(st2[l][lg],st2[r-(1<<lg)+1][lg]);
    	}
    }ST;
    inline bool Check1(LL p,LL x){
    	if(!(p^x)) return true;
    	LL lt=ST.Query1(2*x-p+1,x)+dis[x];
    	LL rt=ST.Query2(x,p-1)-dis[x];
    	LL now=ST.Query2(p,p)-dis[x];
    	if(lt<=now||rt<=now) return false;
    	if(2*x-p>=1) return ST.Query1(2*x-p,2*x-p)+dis[x]>=now;
    	return true;
    }
    inline bool Check2(LL p,LL x){
    	if(!(p^x)) return true;
    	LL lt=ST.Query1(p+1,x)+dis[x];
    	LL rt=ST.Query2(x,2*x-p-1)-dis[x];
    	LL now=ST.Query1(p,p)+dis[x];
    	if(lt<=now||rt<=now) return false;
    	if(2*x-p<=n) return ST.Query2(2*x-p,2*x-p)-dis[x]>now;
    	return true;
    }
    inline LL Solve1(LL p){
    	LL l(1),r(p),ret(p);
    	while(l<=r){
    		LL mid(l+r>>1);
    		if(Check1(p,mid)) r=mid-1,ret=mid;
    		else l=mid+1;
    	}return ret;
    }
    inline LL Solve2(LL p){
    	LL l(p),r(n),ret(p);
    	while(l<=r){
    		LL mid(l+r>>1);
    		if(Check2(p,mid)) l=mid+1,ret=mid;
    		else r=mid-1;
    	}return ret;
    }
    int main(){
    	n=Read(),q=Read();
    	for(LL i=2;i<=n;++i)
    	    dis[i]=dis[i-1]+Read();
    	while(q--){
    		K=Read();
    		for(LL i=1;i<=K;++i) a[i]=(node){Read(),Read()};
    		sort(a+1,a+1+K);
    		ST.Init();
    		LL ret(0);
    		for(LL i=1;i<=K;++i) ret+=(Solve2(a[i].p)-Solve1(a[i].p)+1);
    		printf("%lld
    ",ret);
    	}return 0;
    }
    
  • 相关阅读:
    面向对象程序设计寒假作业2
    终于开通了园子里的贴号
    java中与类继承相关的知识点
    动态代理机制之查看一个类或接口中有哪些方法
    动态代理
    xml与html的区别
    深入理解linux i节点(inode)
    netstat命令
    关于C++ const 的全面总结
    linux 下 进程和线程的区别
  • 原文地址:https://www.cnblogs.com/y2823774827y/p/10339839.html
Copyright © 2020-2023  润新知