#主席树,并查集#CodeChef Sereja and Ballons
分析
考虑用并查集维护当前连续被打破的气球段,那么每次新增的区间就是 \([l_{x-1},x]\) 到 \([x,r_{x+1}]\) 的连接。
只要 \(l,r\) 分别满足在这之间即可,可以用主席树维护一维,另一维直接前缀相减即可,时间复杂度 \(O((m+Q)\log n)\)
代码
#include <cstdio>
#include <cctype>
using namespace std;
const int N=100011; struct node{int y,next;}e[N];
int n,m,a[N],f[N],cnt,rt[N],lans,siz[N],as[N];
int iut(){
int ans=0,f=1; char c=getchar();
while (!isdigit(c)) f=(c=='-')?-f:f,c=getchar();
while (isdigit(c)) ans=ans*10+c-48,c=getchar();
return ans*f;
}
void print(int ans){
if (ans>9) print(ans/10);
putchar(ans%10+48);
}
int getf(int u){return f[u]==u?u:f[u]=getf(f[u]);}
int main(){
n=iut(),m=iut();
for (int i=1;i<=n;++i) a[i]=iut(),f[i]=i,siz[i]=1;
for (int i=1;i<=m;++i){
int l=iut(),r=iut();
e[i]=(node){l,as[r]},as[r]=i;
}
for (int i=1;i<=n;++i){
rt[i]=rt[i-1];
for (int j=as[i];j;j=e[j].next)
update(rt[i],1,n,e[j].y);
}
for (int Q=iut();Q;--Q){
int x=iut()+lans; --a[x];
if (x>1&&!a[x+1]&&!a[x-1]){
int _x=getf(x-1);
lans+=query(rt[x-1],rt[x+siz[x+1]],1,n,_x,x);
f[x]=f[x+1]=_x,siz[_x]+=siz[x+1]+1;
}else if (!a[x+1]){
lans+=query(rt[x-1],rt[x+siz[x+1]],1,n,x,x);
siz[x]=siz[x+1]+1,f[x+1]=x;
}else if (x>1&&!a[x-1]){
int _x=getf(x-1);
lans+=query(rt[x-1],rt[x],1,n,_x,x);
++siz[_x],f[x]=_x;
}else lans+=query(rt[x-1],rt[x],1,n,x,x);
print(lans),putchar(10);
}
return 0;
}