#主席樹,並查集#CodeChef Sereja and Ballons
阿新 • • 發佈:2022-03-15
分析
考慮用並查集維護當前連續被打破的氣球段,那麼每次新增的區間就是 \([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; }