晚間測試13 A. Dove 打撲克 vector +模擬

liuchanglc發表於2020-10-29

題目描述


分析

這道題比較關鍵的一點就是要看出最終牌數的種類數不會超過 \(\sqrt{n}\)
知道了這個性質我們就可以用 \(vector\) 維護一個有序的序列
\(vector\) 中存放牌數的大小和有多少堆這樣的牌
每次二分插入和刪除即可
時間複雜度 \(O(m\sqrt{n})\)

程式碼

#include<cstdio>
#include<vector>
#define rg register
inline int read(){
	rg int x=0,fh=1;
	rg char ch=getchar();
	while(ch<'0' || ch>'9'){
		if(ch=='-') fh=-1;
		ch=getchar();
	}
	while(ch>='0' && ch<='9'){
		x=(x<<1)+(x<<3)+(ch^48);
		ch=getchar();
	}
	return x*fh;
}
const int maxn=1e6+5;
int n,m,tp,siz[maxn],sum[maxn],fa[maxn],sta[maxn];
int zhao(int xx){
	if(xx==fa[xx]) return xx;
	return fa[xx]=zhao(fa[xx]);
}
struct jie{
	int val,cnt;
	jie(){}
	jie(int aa,int bb){
		val=aa,cnt=bb;
	}
};
std::vector<jie> g;
int ef(int val){
	rg int l=1,r=g.size(),mids;
	while(l<=r){
		mids=(l+r)>>1;
		if(g[mids-1].val>=val) r=mids-1;
		else l=mids+1;
	}
	return l-1;
}
int main(){
	n=read(),m=read();
	for(rg int i=1;i<=n;i++){
		siz[i]=1;
		fa[i]=i;
	}
	g.insert(g.begin(),jie(1,n));
	rg int aa,bb,cc,dd,ee,ff;
	rg long long ans=0;
	for(rg int i=1;i<=m;i++){
		aa=read();
		if(aa==1){
			bb=read(),cc=read();
			dd=zhao(bb),ee=zhao(cc);
			if(dd==ee) continue;
			ff=ef(siz[dd]);
			g[ff].cnt--;
			if(g[ff].cnt==0) g.erase(g.begin()+ff);
			ff=ef(siz[ee]);
			g[ff].cnt--;
			if(g[ff].cnt==0) g.erase(g.begin()+ff);
			siz[dd]+=siz[ee];
			siz[ee]=0;
			if(g[g.size()-1].val<siz[dd]){
				g.push_back(jie(siz[dd],1));
			} else {
				ff=ef(siz[dd]);
				if(g[ff].val==siz[dd]) g[ff].cnt++;
				else g.insert(g.begin()+ff,jie(siz[dd],1));
			}
			fa[ee]=dd;
		} else {
			bb=read();
			ans=0;
			tp=g.size();
			for(rg int j=1;j<=tp;j++){
				sum[j]=sum[j-1]+g[j-1].cnt;
				sta[j]=g[j-1].val;
			}
			if(bb==0){
				ans+=1LL*(sum[tp]-1)*sum[tp]/2LL;
			} else {
				ee=1,ff=1;
				while(ee<=tp){
					while(sta[ff]-sta[ee]<bb && ff<=tp) ff++;
					if(sta[ff]-sta[ee]<bb || ff>tp) break;
					ans+=1LL*(sum[ee]-sum[ee-1])*(sum[tp]-sum[ff-1]);
					ee++;
				}
			}
			printf("%lld\n",ans);
		}
	}
	return 0;
}

相關文章