题解:P9530 [JOIST 2022] 鱼 2 / Fish 2
ini2015_____ · · 题解
好牛的题。
一个很厉害的想法是,直接上线段树,我们尝试把两个区间的答案进行合并。
你对于一个区间
显然我们把所有鱼按照
这样子的话,我们可以用一个 vector 存所有等价类,然后考虑合并这些等价类。
考虑怎么维护,我们大概要支持左边节点
时间复杂度
我比较懒,合并的时候多了一个
const int N=2e5+5;
const ll inf=1e16+7;
int n,m,T;
ll v[N];
struct Info{
int p,c;
ll s;
bool operator<(Info x){return p<x.p;}
};
struct Node{
int l,r,c;
vector<Info> L,R;
}tr[N<<2];
void upd(vector<Info>& s){
sort(s.begin(),s.end());
vector<Info> sq;
int ls=-1;
for(auto u:s){
if(u.p==ls)sq.back().c+=u.c;
else sq.pb(u),ls=u.p;
}
s=sq;
}
Node operator+(Node a,Node b){
Node x;
x.r=b.r,x.l=a.l; x.c=0;
vector<Info> &xl=x.L,&xr=x.R;
for(auto u:a.L)if(u.p!=a.r)xl.pb(u);
for(auto u:b.R)if(u.p!=b.l)xr.pb(u);
int ml=v[x.l-1],mr=v[x.r+1];
v[x.l-1]=inf,v[x.r+1]=inf;
int L=0,R=-1;
for(int i=0;i< a.R.size();i++){
Info u=a.R[i]; chkmax(L,i);
if(u.s>=v[b.l]){
R=0;
while(1){
ll ns=a.R[L].s+b.L[R].s;
if(R!=b.L.size() && ns>=v[b.L[R].p+1])R++;
else if(L!=a.R.size() && ns>=v[a.R[L].p-1])L++;
else break;
}
}
ll ns=a.R[L].s+((R>=0)?b.L[R].s:0);
if(L==a.R.size()-1 && R==b.L.size()-1)x.c+=u.c;
if(R==b.L.size()-1)xr.pb(Info{(L>=0)?a.R[L].p:b.l,u.c,ns});
if(L==a.R.size()-1)xl.pb(Info{(R>=0)?b.L[R].p:a.r,u.c,ns});
}
L=-1,R=0;
for(int i=0;i< b.L.size();i++){
Info u=b.L[i]; chkmax(R,i);
if(u.s>=v[a.r]){
L=0;
while(1){
ll ns=a.R[L].s+b.L[R].s;
if(R!=b.L.size() && ns>=v[b.L[R].p+1])R++;
else if(L!=a.R.size() && ns>=v[a.R[L].p-1])L++;
else break;
}
}
ll ns=((L>=0)?a.R[L].s:0)+b.L[R].s;
if(L==a.R.size()-1 && R==b.L.size()-1)x.c+=u.c;
if(R==b.L.size()-1)xr.pb(Info{(L>=0)?a.R[L].p:b.l,u.c,ns});
if(L==a.R.size()-1)xl.pb(Info{(R>=0)?b.L[R].p:a.r,u.c,ns});
}
upd(xl),upd(xr); reverse(xr.begin(),xr.end());
v[x.l-1]=ml,v[x.r+1]=mr;
return x;
}
#define mid ((l+r)>>1)
#define lson u<<1,l,mid
#define rson u<<1|1,mid+1,r
#define root 1,1,n
void pushup(int u){
tr[u]=tr[u<<1]+tr[u<<1|1];
}
void setup(int u,int l){
tr[u].c=1;
tr[u].l=tr[u].r=l;
tr[u].L.clear(),tr[u].R.clear();
tr[u].L.pb(Info{l,1,v[l]});
tr[u].R.pb(Info{l,1,v[l]});
}
void build(int u,int l,int r){
if(l==r)return setup(u,l);
build(lson),build(rson);
pushup(u);
}
void modify(int u,int l,int r,int x,int v){
if(l==r)return setup(u,l);
if(x<=mid)modify(lson,x,v);
if(x> mid)modify(rson,x,v);
pushup(u);
}
Node query(int u,int l,int r,int x,int y){
if(x<=l&&r<=y)return tr[u];
if(x> mid)return query(rson,x,y);
if(y<=mid)return query(lson,x,y);
return query(lson,x,y)+query(rson,x,y);
}
int main(){
n=read();
for(int i=1;i<=n;i++)v[i]=read();
m=read();
build(root);
while(m--){
int o=read(),x=read(),y=read();
if(o==1)v[x]=y,modify(root,x,y);
if(o==2)printf("%d\n",query(root,x,y).c);
}
return 0;
}
// Think twice,code once
::::