zoukankan      html  css  js  c++  java
  • 「JOI 2021 Final」地牢 3

    「JOI 2021 Final」地牢 3

    判定无解

    无解即:(exists iin[S,T-1],A_i>U)

    是一个简单的区间最值问题

    [ ]

    (O(nm))

    关于用单调队列之类的东西维护每个点权值的方法这里就不提了

    形式化地,我们把一层层点放到数轴上,令(X_i=sum_{j<i}A_j)

    在数轴上坐标每(+1)消耗一点能量,我们要从(X_S)走到(X_T)

    考虑每个点的情况,不妨看做是用(B_i)去覆盖((X_S,X_T]),求最小权值

    发现对于(B_i),它能够合法覆盖的区间一定是((X_i,X_i+U])

    暴力地,可以直接让(B_i)更新这段区间的最小权值,然后暴力求和

    [ ]

    进一步分析每个(B_i)覆盖的区间,可以发现是合法区间((X_i,X_i+U])中的某一连续段((L_i,R_i])

    (L_i)取决于(B_i)前面第一个(B_{pre}<B_i)(R_i)取决于后面第一个(B_{nxt}leq B_i)

    关于(pre,nxt)的求解显然只是一个单调栈解决

    得到((L_i,R_i])简单的描述

    (L_i=max{X_i,X_{pre}+U})

    (R_i=min{X_i+U,X_{nxt}})

    (ps:这样求得的(L_i)不一定(<R_i))

    暴力枚举即可(O(n))查询

    [ ]

    [ ]

    (T_i=n+1) 从这里开始需要一些数据结构?

    考虑倒着从(n)(1)计算每一个(S_i)的答案

    发现在刚插入(i)的时候,(pre_i)还未出现,可以看做(-infty)(nxt_i)已经确定

    (pre_i)出现时可以重新进行一次插入

    每次插入可以用三元组表示((i,pre,nxt)),为了便于叙述这里(pre,nxt)直接是坐标

    考虑对于(L_i,R_i)进行参数分离计算,首先要考虑何时满足(L_i<R_i)

    显然条件就是(nxt-pre>U)

    (displaystyle L_i=max{X_i,X_{pre}+U}=X_{pre}+max{X_i-X_{pre},U})

    (displaystyle R_i=min{X_i+U,X_{nxt}}=X_i+min{U,X_{nxt}-X_i})

    (displaystyle Answer=sum_{nxt-pre>U} (R_i-L_i)cdot B_i)

    离线询问,离散之后可以用树状数组维护上述式子,对于不合法部分不要加入即可

    [ ]

    [ ]

    (O(nlog n))

    上面已经能计算(T_i=n+1)的询问,考虑将(S,T)转化为(T_{i}=n+1)的问题

    如果直接(S,T)相减显然不合法,不妨找到在((S,n+1))的方案中,覆盖的(T)的点(T')

    ((S,n+1)-(T',n+1))会抵消掉在(S)的方案中(T)右边的部分,而((X_{T'},X_T])显然仍然是由(B_{T'})覆盖,补回来即可

    由此完成分离操作,而根据上面区间覆盖的定义,(T')实际上就是((X_T-U,X_T])中最小的(B_i)

    所有操作都可以(O(nlog n))完成

    #include<bits/stdc++.h>
    using namespace std;
    
    typedef long long ll;
    typedef unsigned long long ull;
    typedef double db;
    typedef pair <int,int> Pii;
    #define mp make_pair
    #define pb push_back
    #define Mod1(x) ((x>=P)&&(x-=P))
    #define Mod2(x) ((x<0)&&(x+=P))
    #define rep(i,a,b) for(int i=a,i##end=b;i<=i##end;++i)
    #define drep(i,a,b) for(int i=a,i##end=b;i>=i##end;--i)
    template <class T> inline void cmin(T &a,T b){ ((a>b)&&(a=b)); }
    template <class T> inline void cmax(T &a,T b){ ((a<b)&&(a=b)); }
    
    char IO;
    int rd(){
    	int s=0,f=0;
    	while(!isdigit(IO=getchar())) f|=IO=='-';
    	do s=(s<<1)+(s<<3)+(IO^'0');
    	while(isdigit(IO=getchar()));
    	return f?-s:s;
    }
    
    const int N=2e5+10,INF=1e9+10;
    
    int n,m,A[N],B[N],nxt[N],stk[N],top,C;
    ll ans[N],X[N],H[N];
    struct Node{ int U,k,id; };
    vector <Node> Q[N];
    vector <int> G[N];
    struct BIT{
    	ll s[N];
    	void Add(int p,ll x){ 
    		while(p<=C) s[p]+=x,p+=p&-p; 
    	}
    	ll Que(int p){
    		ll res=0;
    		while(p) res+=s[p],p-=p&-p;
    		return res;
    	}
    } T1,T2;
    // T1维护式子中含U项的和
    // T2维护式子中常数和
    
    struct MaxTree{
    	int s[N<<2],bit;
    	void Build(){
    		for(bit=1;bit<=n+1;bit<<=1) ;
    		rep(i,1,n) s[bit+i]=A[i];
    		drep(i,bit,1) s[i]=max(s[i<<1],s[i<<1|1]);
    	}
    	int Que(int l,int r){
    		if(l==r) return s[l+bit];
    		int res=0;
    		for(l+=bit-1,r+=bit+1;l^r^1;l>>=1,r>>=1){
    			if(~l&1) cmax(res,s[l^1]);
    			if(r&1) cmax(res,s[r^1]);
    		}
    		return res;
    	}
    } Max;
    struct MinTree{
    	int s[N<<2],bit;
    	int Min(int x,int y){ return mp(B[x],x)<mp(B[y],y)?x:y; }
    	void Build(){
    		B[0]=1e9;
    		for(bit=1;bit<=n+1;bit<<=1) ;
    		rep(i,1,n) s[bit+i]=i;
    		drep(i,bit,1) s[i]=Min(s[i<<1],s[i<<1|1]);
    	}
    	int Que(int l,int r){
    		if(l==r) return s[l+bit];
    		int res=0;
    		for(l+=bit-1,r+=bit+1;l^r^1;l>>=1,r>>=1){
    			if(~l&1) res=Min(res,s[l^1]);
    			if(r&1) res=Min(res,s[r^1]);
    		}
    		return res;
    	}
    } Min;
    // Min 用于寻找T'
    
    void Add(int i,ll pre,ll nxt,int k){
    	int p=lower_bound(H+1,H+C+1,X[i]-pre)-H,r=lower_bound(H+1,H+C+1,nxt-pre)-H;
    	// -L
    	T1.Add(p,-B[i]*k), T1.Add(r,B[i]*k);
    	T2.Add(p,k*B[i]*(X[i]-pre)), T2.Add(r,-k*B[i]*(X[i]-pre));
    	// +R 
    	p=lower_bound(H+1,H+C+1,nxt-X[i])-H;
    	T1.Add(1,k*B[i]),T1.Add(p,-k*B[i]);
    	T2.Add(p,k*(nxt-X[i])*B[i]),T2.Add(r,-k*(nxt-X[i])*B[i]);
    }
    
    int main(){
    	n=rd(),m=rd();
    	rep(i,1,n) A[i]=rd(),X[i+1]=X[i]+A[i];
    	rep(i,1,n) B[i]=rd();
    	drep(i,n+1,1) {
    		while(top && B[stk[top]]>=B[i]) G[i].pb(stk[top--]);
    		nxt[i]=stk[top],stk[++top]=i;
    	}
    	Min.Build(),Max.Build();
    	rep(i,1,m) {
    		int S=rd(),T=rd(),U=rd();
    		if(Max.Que(S,T-1)>U){ ans[i]=-1; continue; }
    		H[++C]=U,Q[S].pb((Node){U,1,i});
    		int l=lower_bound(X+1,X+n+2,X[T]-U)-X; cmax(l,S);
    		int t=Min.Que(l,T);
    		ans[i]+=(X[T]-X[t])*B[t];
    		Q[t].pb((Node){U,-1,i});
    	}
    	sort(H+1,H+C+1),C=unique(H+1,H+C+1)-H-1;
    	drep(i,n,1){
    		Add(i,-1e9,X[nxt[i]],1);
    		for(int j:G[i]) Add(j,-1e9,X[nxt[j]],-1),Add(j,X[i],X[nxt[j]],1);
    		for(Node j:Q[i]){
    			int p=lower_bound(H+1,H+C+1,j.U)-H;
    			ans[j.id]+=j.k*(j.U*T1.Que(p)+T2.Que(p));
    		}
    	}
    	rep(i,1,m) printf("%lld
    ",ans[i]);
    }
    
  • 相关阅读:
    【BZOJ 4151 The Cave】
    【POJ 3080 Blue Jeans】
    【ZBH选讲·树变环】
    【ZBH选讲·拍照】
    【ZBH选讲·模数和】
    【CF Edu 28 C. Four Segments】
    【CF Edu 28 A. Curriculum Vitae】
    【CF Edu 28 B. Math Show】
    【CF Round 439 E. The Untended Antiquity】
    【CF Round 439 C. The Intriguing Obsession】
  • 原文地址:https://www.cnblogs.com/chasedeath/p/14435913.html
Copyright © 2011-2022 走看看