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]);
    }
    
  • 相关阅读:
    EntityFramework4.5使用Expression类创建动态查询及动态查询导航属性
    EF 5.0 帮助类
    EF异常:“System.InvalidOperationException”类型的未经处理的异常在 mscorlib.dll 中发生
    EF框架学习手记
    Entity Framework 学习
    C#特性-表达式树
    LINQ to SQL 运行时动态构建查询条件
    一点css 基础
    JQuery 判断复选框是否选中
    Asp.Net Server.MapPath()用法
  • 原文地址:https://www.cnblogs.com/chasedeath/p/14435913.html
Copyright © 2011-2022 走看看