[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 } 
View Code

 

posted @ 2022-04-10 13:24  PYWBKTDA  阅读(86)  评论(0编辑  收藏  举报