题解:P8473 [Aya Round 1 H] 破碎的历史
线段树好题。
跟二分配在一起有点阴间。。。
Solution
注意到一个重要性质:每次添加
因此我们可以每次二分寻找
实现上有许多细节,具体可以看我的代码。
AC code
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int MAXN=5e5+5;
int n,q,opt,l,r,x,p[MAXN],ll[MAXN],rr[MAXN],qzh[MAXN],tree[4*MAXN],a[MAXN],tag[4*MAXN];
inline int lc(int x){return x<<1;}
inline int rc(int x){return x<<1|1;}
inline void push_up(int now){tree[now]=min(tree[lc(now)],tree[rc(now)]);}
inline void f(int now,int k){tree[now]+=k,tag[now]+=k;}
inline void push_down(int now){
f(lc(now),tag[now]);
f(rc(now),tag[now]);
tag[now]=0;
}
inline void build(int l,int r,int now){
if(l==r){
tree[now]=a[l];
return;
}
int mid=l+r>>1;
build(l,mid,lc(now));
build(mid+1,r,rc(now));
push_up(now);
}
inline void update(int l,int r,int now,int nl,int nr,int k){
if(l>nr||r<nl) return;
if(l>=nl&&r<=nr){
f(now,k);
return;
}
push_down(now);
int mid=l+r>>1;
update(l,mid,lc(now),nl,nr,k);
update(mid+1,r,rc(now),nl,nr,k);
push_up(now);
}
int find1(int x){
int l=x,r=n,res=1e9;
while(l<=r){
int mid=l+r>>1;
if(qzh[mid]!=qzh[x-1]) r=mid-1,res=mid;
else l=mid+1;
}
return res;
}
int find2(int x){
int l=1,r=x,res=1e9;
while(l<=r){
int mid=l+r>>1;
if(qzh[mid-1]!=qzh[x]) l=mid+1,res=mid;
else r=mid-1;
}
return res;
}
signed main(){
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
cin>>n>>q;
for(int i = 1;i<=n;i++) cin>>p[i];
for(int i = 1;i<=n;i++) cin>>a[i],qzh[i]=qzh[i-1]+a[i];//qzh 用于判断 l 和 r 之间是否有 1,判断为:qzh[l-1]!=qzh[r]
build(1,n,1);
if(tree[1]) cout<<"Yes\n";
else cout<<"No\n";
for(int i = 1;i<=q;i++){
cin>>opt;
if(opt==1){
cin>>l>>r;
int tmpl=lower_bound(p+1,p+1+n,l)-p,tmpr=upper_bound(p+1,p+1+n,r)-p-1;
//tmpl 表示 l 右边的第一个特殊整点,tmpr 表示 r 左边的第一个特殊整点
bool flag=1;
if(p[tmpl]>r||p[tmpr]<l){//判断越界情况
ll[i]=-1,rr[i]=-1;
flag=0;
}
ll[i]=find1(tmpl),rr[i]=find2(tmpr);//寻找 tmpl 和 tmpr 之间最大的黑色的区间
if(ll[i]>tmpr||rr[i]<tmpl||ll[i]==1e9||rr[i]==1e9||ll[i]>rr[i]){//判断不合法情况
ll[i]=-1,rr[i]=-1;
flag=0;
}
if(flag) update(1,n,1,ll[i],rr[i],1);
}
else{
cin>>x;
if(ll[x]!=1e9) update(1,n,1,ll[x],rr[x],-1);
}
if(tree[1]) cout<<"Yes\n";
else cout<<"No\n";
}
return 0;
}