題解 CF1556E 【Equilibrium】
阿新 • • 發佈:2021-08-30
題目意思:
有 \(n\) 組數 \(a_1,a_2,\cdots,a_n\) 和 \(b_1,b_2,\cdots,b_n\),\(q\) 次獨立的詢問,每次詢問區間 \(l\sim r\),求多少次“平衡操作”使得每個滿足 \(l\le i\le r\) 的 \(i\) 都有 \(a_i=b_i\),無法完成輸出
-1
。平衡操作指的是給出一個長度為偶數位置序列 \(l\le pos_1<pos_2<\cdots<pos_k\le r\),進行操作:\(a_{pos_1},a_{pos_3},a_{pos_5},\cdots\) 加上 1,\(b_{pos_2}\) 加上 1。
我們發現如果 \(a_i\) 減去 1,那麼就相當於是 \(a_i-b_i\) 減去 \(1\)。我們發現如果 \(b_i\) 減去 1,那麼就相當於是 \(a_i-b_i\) 加上 \(1\),最終要讓每個滿足 \(l\le i\le r\) 的 \(i\) 都有 \(a_i-b_i=0\)。
我們去觀察它的操作序列,實際上這些元素是分成了若干個組,比如 \(po s_1\) 和 \(pos_2\)。
我們把 \(a_i-b_i\) 這個東西字首和一下,\(s_i\) 表示 \((a_1-b_1)+(a_2-b_2)+\cdots+(a_i-b_i)\),就會發現每組操作 \(pos_1,pos_2\)
判 -1
就是 2 種情況:
- \(s_r\ne s_{l-1}\)
- \(\max\limits_{i=l}^{r}\{s_i\}>s_{l-1}\) (因為是區間加 1)
答案是 \(s_{l-1}-\min\limits_{i=l}^{r}\{s_i\}\),都不是很困難。
區間查詢 \(\max\) 和 \(\min\),用 ST 表實現即可。
#include<bits/stdc++.h> #define int long long #define log(a) cerr<<"[DEBUG] "<<#a<<'='<<(a)<<" @ line "<<__LINE__<<endl using namespace std; typedef long long LL; template<typename T>void chkmax(T&x,T y){x=max(x,y);} template<typename T>void chkmin(T&x,T y){x=min(x,y);} template<typename T>inline void read(T &FF){ T RR=1;FF=0;char CH=getchar(); for(;!isdigit(CH);CH=getchar())if(CH=='-')RR=-1; for(;isdigit(CH);CH=getchar())FF=(FF<<1)+(FF<<3)+(CH^48); FF*=RR; } const int N=1e5+10,M=25; int a[N],f[N],lg[N],mxn[M][N],mnn[M][N]; pair<int,int>query(int l,int r){ int len=lg[r-l+1]; return make_pair(max(mxn[len][l],mxn[len][r-(1<<len)+1]),min(mnn[len][l],mnn[len][r-(1<<len)+1])); } signed main(){ int n,q; read(n);read(q); for(int i=2;i<=n;i++)lg[i]=lg[i>>1]+1; for(int i=1;i<=n;i++)read(a[i]); for(int i=1,x;i<=n;i++){ read(x); a[i]-=x; f[i]=f[i-1]+a[i]; } // cout<<"->f";for(int i=1;i<=n;i++)cout<<f[i]<<" ";cout<<endl; for(int i=0;i<=20;i++) for(int j=1;j+(1<<i)-1<=n;j++) if(i==0)mxn[i][j]=mnn[i][j]=f[j]; else{ mxn[i][j]=max(mxn[i-1][j],mxn[i-1][j+(1<<(i-1))]); mnn[i][j]=min(mnn[i-1][j],mnn[i-1][j+(1<<(i-1))]); } // log(mnn[2][2]); while(q--){ int l,r; read(l);read(r); pair<int,int>a=query(l,r); // log(a.first);log(a.second); if(f[r]!=f[l-1]||a.first>f[l-1])puts("-1"); else cout<<f[l-1]-a.second<<endl; } return 0; }