[loj3695]鱼
对于Subtask2,考虑如下做法——
称$[l,r]$为"坏区间"当且仅当$\sum_{i=l}^{r}a_{i}<a_{l-1},a_{r+1}$($a_{0}$和$a_{n+1}$看作$\infty$)
此时,不难证明第$i$条鱼能存活当且仅当不存在覆盖$i$的坏区间(除$[1,n]$外)
如何求出坏区间:枚举左端点$l$,并不断找到下一个满足$\sum_{i=l}^{r}a_{i}<a_{r+1}$的右端点$r$
记$s_{i}=\sum_{j=1}^{i}a_{j}$,条件也即$s_{r}-a_{r+1}<s_{l-1}$,维护$s_{r}-a_{r+1}$并在线段树上二分即可
记值域为$A$,注意到每次$\sum_{i=l}^{r}a_{i}$至少乘2,因此至多找$o(\log A)$次
(上述找右端点的过程将会多次出现,简称其为$P$过程,并拓展到找左端点上)
求出$r$后判定$\sum_{i=l}^{r}a_{i}<a_{l-1}$并差分覆盖,时间复杂度为$o(n\log n\log A)$,可以通过
顺便一提,实际上可以做到$o(n)$,将坏区间按照$a_{l-1}$和$a_{r+1}$的大小关系分类即可
关于Subtask4,考虑如下做法——
对于询问$[L,R]$,内部的坏区间分为两类:
1.以$L,R$为端点(因为$a_{L-1}$和$a_{R+1}$被看作$\infty$)
这类区间可以用$P$过程求出,并记其中最大的区间分别为$[L,L')$和$(R',R]$
2.$\subseteq [L,R]$的全局坏区间(显然$a_{L-1}$和$a_{R+1}$被看作$\infty$仍是坏区间)
由于$[L,L')$和$(R',R]$已经被覆盖,即仅需考虑还与$[L',R']$有交的(全局)坏区间
性质1:坏区间两两包含或相离
反证法,假设坏区间$[l_{1},r_{1}]$和$[l_{2},r_{2}]$满足$l_{1}<l_{2}\le r_{1}<r_{2}$
结合坏区间的条件,分析$a_{l_{2}-1}$和$a_{r_{1}+1}$的大小关系,显然矛盾
推论1:坏区间中与$[L',R']$有交的区间均包含$[L',R']$或被$[L',R']$包含
(其实并不能根据性质1直接得到,但证明类似)
根据推论1,答案即$[L',R']$(在所有坏区间中)覆盖次数最少的位置数(最大的鱼总可以存活)
使用线段树维护覆盖次数即可,时间复杂度为$o(n\log n\log A+m\log n)$,可以通过
对于Subtask6,考虑如下做法——
在带修改时,显然$P$过程仍可以实现,进而问题即维护覆盖次数(也即坏区间)
假设修改为$a_{x}=y$,暴力找出所有与$x$相关的坏区间,并依次执行删除-修改-加入即可
具体的,与$x$相关的坏区间分为两类:
1.以$x\pm 1$为左/右端点,这类区间可以用$P$过程求出(并需要判定)
2.包含$x$,用$P$过程分别求出以$x$为端点时的左右端点(不以$x$为端点条件更严)
性质2:包含$x$的坏区间仅有$o(\log A)$个
结合性质1,这些区间也相互包含,按长度排序后每次权值和乘2,即得证
根据性质2,暴力枚举这$o(\log^{2}A)$个区间,其中仅有$o(\log A)$个会修改覆盖次数
时间复杂度为$o(n\log n\log A+m\log n\log A+m\log^{2}A)$,可以通过
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define N 100005 4 #define ll long long 5 #define pii pair<int,int> 6 #define fi first 7 #define se second 8 #define L (k<<1) 9 #define R (L+1) 10 #define mid (l+r>>1) 11 int n,m,p,x,y,a[N];ll s[N];vector<int>vl,vr; 12 namespace TA{ 13 ll f[N]; 14 int lowbit(int k){ 15 return (k&(-k)); 16 } 17 void update(int k,int x){ 18 while (k<=n)f[k]+=x,k+=lowbit(k); 19 } 20 ll query(int k){ 21 ll ans=0; 22 while (k)ans+=f[k],k^=lowbit(k); 23 return ans; 24 } 25 void build(){ 26 for(int i=1;i<=n;i++)f[i]=s[i]-s[i^lowbit(i)]; 27 } 28 }; 29 namespace Left{ 30 ll tag[N<<2],mn[N<<2]; 31 void build(int k,int l,int r){ 32 if (l==r){ 33 mn[k]=s[l]-a[l+1]; 34 if (l==n)mn[k]=-1e16; 35 return; 36 } 37 build(L,l,mid),build(R,mid+1,r); 38 mn[k]=min(mn[L],mn[R]); 39 } 40 void update(int k,int l,int r,int x,int y,int z){ 41 if ((l>y)||(x>r))return; 42 if ((x<=l)&&(r<=y)){ 43 tag[k]+=z,mn[k]+=z; 44 return; 45 } 46 update(L,l,mid,x,y,z),update(R,mid+1,r,x,y,z); 47 mn[k]=min(mn[L],mn[R])+tag[k]; 48 } 49 int query(int k,int l,int r,int x,ll y){ 50 if ((r<x)||(y<=mn[k]))return 0; 51 y-=tag[k];if (l==r)return l; 52 int ans=query(L,l,mid,x,y); 53 if (!ans)ans=query(R,mid+1,r,x,y); 54 return ans; 55 } 56 void update(int k,int x){ 57 update(1,1,n,k,n,x),update(1,1,n,k-1,k-1,-x); 58 } 59 void find(int l){ 60 vl.clear(); 61 ll s=TA::query(l-1); 62 while (1){ 63 l=query(1,1,n,l,s); 64 if (!l)break;vl.push_back(l++); 65 } 66 } 67 }; 68 namespace Right{ 69 ll tag[N<<2],mx[N<<2]; 70 void build(int k,int l,int r){ 71 if (l==r){ 72 mx[k]=s[l-1]+a[l-1]; 73 if (l==1)mx[k]=1e16; 74 return; 75 } 76 build(L,l,mid),build(R,mid+1,r); 77 mx[k]=max(mx[L],mx[R]); 78 } 79 void update(int k,int l,int r,int x,int y,int z){ 80 if ((l>y)||(x>r))return; 81 if ((x<=l)&&(r<=y)){ 82 tag[k]+=z,mx[k]+=z; 83 return; 84 } 85 update(L,l,mid,x,y,z),update(R,mid+1,r,x,y,z); 86 mx[k]=max(mx[L],mx[R])+tag[k]; 87 } 88 int query(int k,int l,int r,int x,ll y){ 89 if ((l>x)||(mx[k]<=y))return 0; 90 y-=tag[k];if (l==r)return l; 91 int ans=query(R,mid+1,r,x,y); 92 if (!ans)ans=query(L,l,mid,x,y); 93 return ans; 94 } 95 void update(int k,int x){ 96 update(1,1,n,k+1,n,x),update(1,1,n,k+1,k+1,x); 97 } 98 void find(int r){ 99 vr.clear(); 100 ll s=TA::query(r); 101 while (1){ 102 r=query(1,1,n,r,s); 103 if (!r)break;vr.push_back(r--); 104 } 105 } 106 }; 107 namespace Seg{ 108 int cnt[N],tag[N<<2]; 109 pii f[N<<2]; 110 pii merge(pii x,pii y){ 111 pii ans=min(x,y); 112 if (x.fi==y.fi)ans.se=x.se+y.se; 113 return ans; 114 } 115 void build(int k,int l,int r){ 116 if (l==r){ 117 f[k]=make_pair(cnt[l],1); 118 return; 119 } 120 build(L,l,mid),build(R,mid+1,r); 121 f[k]=merge(f[L],f[R]); 122 } 123 void update(int k,int l,int r,int x,int y,int z){ 124 if ((l>y)||(x>r))return; 125 if ((x<=l)&&(r<=y)){ 126 tag[k]+=z,f[k].fi+=z; 127 return; 128 } 129 update(L,l,mid,x,y,z),update(R,mid+1,r,x,y,z); 130 f[k]=merge(f[L],f[R]),f[k].fi+=tag[k]; 131 } 132 pii query(int k,int l,int r,int x,int y){ 133 if ((l>y)||(x>r))return make_pair(1e8,0); 134 if ((x<=l)&&(r<=y))return f[k]; 135 pii ans=merge(query(L,l,mid,x,y),query(R,mid+1,r,x,y)); 136 ans.fi+=tag[k];return ans; 137 } 138 void build(){ 139 for(int i=1;i<=n;i++){ 140 Left::find(i); 141 ll S=s[i-1]+a[i-1];if (i==1)S=1e16; 142 for(int j:vl) 143 if (TA::query(j)<S)cnt[i]++,cnt[j+1]--; 144 } 145 for(int i=1;i<=n;i++)cnt[i]+=cnt[i-1]; 146 build(1,1,n); 147 } 148 void update(int k,int p){ 149 Left::find(k+1),Right::find(k-1); 150 ll S1=TA::query(k)+a[k]; 151 for(int i:vl) 152 if (TA::query(i)<S1)update(1,1,n,k+1,i,p); 153 ll S2=TA::query(k-1)-a[k]; 154 for(int i:vr) 155 if (S2<TA::query(i-1))update(1,1,n,i,k-1,p); 156 Left::find(k),Right::find(k); 157 for(int i:vl)s[i]=TA::query(i); 158 for(int i:vr)s[i-1]=TA::query(i-1); 159 for(int i:vl) 160 for(int j:vr){ 161 ll S=s[i]-s[j-1]; 162 if (((i==n)||(S<a[i+1]))&&((j==1)||(S<a[j-1])))update(1,1,n,j,i,p); 163 } 164 } 165 }; 166 void init(){ 167 for(int i=1;i<=n;i++)s[i]=s[i-1]+a[i]; 168 TA::build(),Left::build(1,1,n),Right::build(1,1,n),Seg::build(); 169 } 170 void update(int k,int x){ 171 Seg::update(k,-1),a[k]+=x; 172 TA::update(k,x),Left::update(k,x),Right::update(k,x),Seg::update(k,1); 173 } 174 int query(int l,int r){ 175 Left::find(l),Right::find(r); 176 if (vl[0]<r)l=(*--lower_bound(vl.begin(),vl.end(),r))+1; 177 if (vr[0]>l){ 178 reverse(vr.begin(),vr.end()); 179 r=(*upper_bound(vr.begin(),vr.end(),l))-1; 180 } 181 return Seg::query(1,1,n,l,r).se; 182 } 183 int main(){ 184 scanf("%d",&n); 185 for(int i=1;i<=n;i++)scanf("%d",&a[i]); 186 init(); 187 scanf("%d",&m); 188 for(int i=1;i<=m;i++){ 189 scanf("%d%d%d",&p,&x,&y); 190 if (p==1)update(x,y-a[x]); 191 if (p==2)printf("%d\n",query(x,y)); 192 } 193 return 0; 194 }