[loj3523]分糖果
將問題離線,並在左端點和右端點打上差分,之後即可以看作求$f(C,[a_{1},a_{2},...,a_{n}])$,其表示以$C$為上限(0為下限),從0開始不斷加上$a_{i}$(可以為負)的答案
再定義$g(C,a_{i})$,其與$f(C,a_{i})$的定義類似,但沒有下限為0的限制
考慮兩者的關係,顯然$\forall 0\le j\le n$有
$$
f(C,[a_{1},a_{2},...,a_{n}])\ge f(C,[a_{j+1},a_{j+2},...,a_{n}])\ge g(C,[a_{j+1},a_{j+2},...,a_{n}])
$$
前者是因為在操作$a_{j-1}$後值非負,後者因為其沒有下限顯然值不增
另一方面,考慮最大的$j$,使得在$f(C,a_{i})$中操作$a_{j}$後值為0,即之後不會再變為0,那麼也可以看作沒有下限為0的限制,即有
$$
f(C,[a_{1},a_{2},...,a_{n}])=f(C,[a_{j+1},a_{j+2},...,a_{n}])=g(C,[a_{j+1},a_{j+2},...,a_{n}])
$$
(若不存在則令$j=0$,相等的原因類似,這裡就省略了)
由此,我們得到了$f(C,[a_{1},a_{2},...,a_{n}])=\max_{0\le j\le n}g(C,[a_{j+1},a_{j+2},...,a_{n}])$
考慮$g(C,[a_{1},a_{2},...,a_{n}])$,令$S_{i}=\sum_{j=1}^{i}a_{j}$,若不存在$S_{i}>C$即為$S_{n}$,否則即$S_{n}-\max_{1\le i\le n}S_{i}+C$
將之代入前式並化簡,也即
$$
f(C,[a_{1},a_{2},...,a_{n}])=S_{n}-\min_{0\le i\le n}\max(S_{i},\max_{i\le j\le n}S_{j}-C)
$$
考慮如何維護,二分列舉答案$T$,那麼$f(C,a_{i})>T$當且僅當
$$
\exists 0\le i\le n,\max(S_{i},\max_{i\le j\le n}S_{j}-C)<S_{n}-T
$$
換言之,我們即要檢驗是否存在$S_{i}<S_{n}-T$且$\forall i\le j\le n,S_{j}<S_{n}-T+C$,顯然後者具有單調性,通過線段樹可以確定$i$的下限,然後求區間最小值即可
時間複雜度為$o(n\log^{2}n)$,可以通過
1 #include<bits/stdc++.h> 2 #include"candies.h" 3 using namespace std; 4 #define N 200005 5 #define ll long long 6 #define L (k<<1) 7 #define R (L+1) 8 #define mid (l+r>>1) 9 vector<int>ans,Add[N],Dec[N]; 10 int n,m; 11 ll tag[N<<2],mx[N<<2],mn[N<<2]; 12 void upd(int k,ll x){ 13 tag[k]+=x; 14 mx[k]+=x; 15 mn[k]+=x; 16 } 17 void up(int k){ 18 mx[k]=max(mx[L],mx[R]); 19 mn[k]=min(mn[L],mn[R]); 20 } 21 void down(int k){ 22 upd(L,tag[k]); 23 upd(R,tag[k]); 24 tag[k]=0; 25 } 26 void update(int k,int l,int r,int x,int y,int z){ 27 if ((l>y)||(x>r))return; 28 if ((x<=l)&&(r<=y)){ 29 upd(k,z); 30 return; 31 } 32 down(k); 33 update(L,l,mid,x,y,z); 34 update(R,mid+1,r,x,y,z); 35 up(k); 36 } 37 ll query(int k,int l,int r,int x,int y){ 38 if ((l>y)||(x>r))return 2e15; 39 if ((x<=l)&&(r<=y))return mn[k]; 40 down(k); 41 return min(query(L,l,mid,x,y),query(R,mid+1,r,x,y)); 42 } 43 int find(int k,int l,int r,ll x){ 44 if (mx[k]<x)return -1; 45 if (l==r)return l; 46 down(k); 47 int ans=find(R,mid+1,r,x); 48 if (ans>=0)return ans; 49 return find(L,l,mid,x); 50 } 51 int query(int k){ 52 int l=0,r=k; 53 ll S=query(1,0,m,m,m); 54 while (l<r){ 55 int x=find(1,0,m,S-mid+k); 56 if (query(1,0,m,x+1,m)>=S-mid)r=mid; 57 else l=mid+1; 58 } 59 return l; 60 } 61 vector<int> distribute_candies(vector<int>c,vector<int>l,vector<int>r,vector<int>v){ 62 n=c.size(),m=l.size(); 63 for(int i=0;i<m;i++){ 64 Add[l[i]].push_back(i); 65 Dec[r[i]].push_back(i); 66 } 67 for(int i=0;i<n;i++){ 68 for(int j=0;j<Add[i].size();j++)update(1,0,m,Add[i][j]+1,m,v[Add[i][j]]); 69 ans.push_back(query(c[i])); 70 for(int j=0;j<Dec[i].size();j++)update(1,0,m,Dec[i][j]+1,m,-v[Dec[i][j]]); 71 } 72 return ans; 73 }View Code