1. 程式人生 > 其它 >#主席樹,並查集#CodeChef Sereja and Ballons

#主席樹,並查集#CodeChef Sereja and Ballons

SEABAL


分析

考慮用並查集維護當前連續被打破的氣球段,那麼每次新增的區間就是 \([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;
}